Portfolio — Victor Ouledi
Jupyter notebook analyse actionnariat
Initializing search
    Repo GitHub
    • Accueil
    • Projets
    • À propos
    • Contact
    Repo GitHub
    • Accueil
      • Aperçu
      • NLP — Classification de plaintes
      • Vision — Imagerie médicale
      • Clustering & ACP — Criminalité aux États-Unis
      • AFC — Élections 2022 (IDF)
      • R — Prix hédoniques (Lyon)
      • R — Salaires (panel US)
      • Analyse — Terre de Liens
      • Certifications
    • À propos
    • Contact
    In [1]:
    Copied!
    %%HTML 
    <script>
        function luc21893_refresh_cell(cell) {
            if( cell.luc21893 ) return;
            cell.luc21893 = true;
            console.debug('New code cell found...' );
            
            var div = document.createElement('DIV');            
            cell.parentNode.insertBefore( div, cell.nextSibling );
            div.style.textAlign = 'right';
            var a = document.createElement('A');
            div.appendChild(a);
            a.href='#'
            a.luc21893 = cell;
            a.setAttribute( 'onclick', "luc21893_toggle(this); return false;" );
    
            cell.style.visibility='hidden';
            cell.style.position='absolute';
            a.innerHTML = '[show code]';        
                    
        }
        function luc21893_refresh() {                
            if( document.querySelector('.code_cell .input') == null ) {            
                // it apeears that I am in a exported html
                // hide this code
                var codeCells = document.querySelectorAll('.jp-InputArea')
                codeCells[0].style.visibility = 'hidden';
                codeCells[0].style.position = 'absolute';                        
                for( var i = 1; i < codeCells.length; i++ ) {
                    luc21893_refresh_cell(codeCells[i].parentNode)
                }
                window.onload = luc21893_refresh;
            }                 
            else {
                // it apperas that I am in a jupyter editor
                var codeCells = document.querySelectorAll('.code_cell .input')
                for( var i = 0; i < codeCells.length; i++ ) {
                    luc21893_refresh_cell(codeCells[i])
                }            
                window.setTimeout( luc21893_refresh, 1000 )
            }        
        }
        
        function luc21893_toggle(a) {
            if( a.luc21893.style.visibility=='hidden' ) {
                a.luc21893.style.visibility='visible';        
                a.luc21893.style.position='';
                a.innerHTML = '[hide code]';
            }
            else {
                a.luc21893.style.visibility='hidden';        
                a.luc21893.style.position='absolute';
                a.innerHTML = '[show code]';
            }
        }
        
        luc21893_refresh()
    </script>
    
    %%HTML
    In [2]:
    Copied!
    from IPython.display import display, HTML
    
    # Afficher un titre centré et sous-ligné avec une taille de police plus grande
    display(HTML('<center><h1>Analyse actionnaires</h1></center>'))
    
    from IPython.display import display, HTML # Afficher un titre centré et sous-ligné avec une taille de police plus grande display(HTML('

    Analyse actionnaires

    '))

    Analyse actionnaires

    In [3]:
    Copied!
    from IPython.display import display, HTML
    
    
    # Insérer une ligne de soulignement
    display(HTML("<hr>"))
    
    from IPython.display import display, HTML # Insérer une ligne de soulignement display(HTML("
    "))

    In [4]:
    Copied!
    import random
    import pandas as pd
    import string
    import numpy as np
    from datetime import datetime, timedelta
    
    
    # Fonction pour générer une combinaison de 6 lettres aléatoires
    def generer_combinaison():
        lettres = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
        return ''.join(random.choice(lettres) for _ in range(6))
    
    # Générer une liste de 20 000 combinaisons de noms complets uniques
    noms_complets = set()
    while len(noms_complets) < 20000:
        nom_complet = f"{generer_combinaison()} {generer_combinaison()}"
        noms_complets.add(nom_complet)
    
    # Répéter aléatoirement les noms complets jusqu'à 12 fois maximum
    noms_complets_repetes = []
    for nom_complet in noms_complets:
        repetitions = random.randint(0, 12)
        noms_complets_repetes.extend([nom_complet] * repetitions)
    
    # Limiter la liste à 20 000 éléments
    noms_complets_final = random.sample(noms_complets_repetes, 20000)
    
    # Créer un DataFrame pandas avec les noms complets
    data = pd.DataFrame({'Nom complet': noms_complets_final})
    # Fonction pour générer une combinaison de 6 lettres aléatoires
    def generer_combinaison():
        lettres = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
        return ''.join(random.choice(lettres) for _ in range(6))
    
    # Générer une liste de 35 combinaisons de noms complets uniques répétées 11 fois
    noms_complets_35 = []
    for _ in range(35):
        nom_complet = f"{generer_combinaison()} {generer_combinaison()}"
        noms_complets_35.extend([nom_complet] * 11)
    
    # Générer une liste de 65 combinaisons de noms complets uniques répétées 12 fois
    noms_complets_65 = []
    for _ in range(65):
        nom_complet = f"{generer_combinaison()} {generer_combinaison()}"
        noms_complets_65.extend([nom_complet] * 12)
    
    # Combiner les deux listes
    noms_complets_final = noms_complets_35 + noms_complets_65
    
    # Créer un DataFrame pandas avec les noms complets
    data2 = pd.DataFrame({'Nom complet': noms_complets_final})
    
    # Concaténer les deux DataFrames
    data = pd.concat([data, data2], ignore_index=True)
    
    # Initialiser un dictionnaire pour suivre les ID du contact par nom complet
    id_du_contact_par_nom = {}
    
    # Générer une liste de noms complets avec répétition
    noms_complets = data['Nom complet']
    
    # Générer une liste d'ID de contact basée sur les noms complets (mêmes noms auront les mêmes ID)
    ids_contacts = [''.join(random.choices(string.ascii_uppercase + string.digits, k=10)) + ''.join(random.choices(string.ascii_uppercase, k=2)) for _ in range(21165)]
    
    # Remplir le dictionnaire ID du contact par nom complet
    for nom_complet, id_contact in zip(noms_complets, ids_contacts):
        if nom_complet not in id_du_contact_par_nom:
            id_du_contact_par_nom[nom_complet] = id_contact
    
    # Utiliser le dictionnaire pour obtenir les ID du contact pour chaque nom complet
    data['ID du contact'] = [id_du_contact_par_nom[nom_complet] for nom_complet in noms_complets]
    
    # Créer une colonne 'âge' en attribuant un âge aléatoire entre 0 et 90 à chaque ID du contact unique
    unique_ids = data['ID du contact'].unique()
    ages = [random.randint(0, 90) for _ in range(len(unique_ids))]
    
    # Créer un dictionnaire pour associer chaque ID du contact à son âge
    id_to_age = dict(zip(unique_ids, ages))
    
    # Appliquer l'âge correspondant à chaque ID du contact dans le DataFrame original
    data['âge'] = data['ID du contact'].map(id_to_age)
    
    territoires = [
        "Alsace", "Aquitaine", "Auvergne", "Basse-Normandie", "Bourgogne", "Bretagne", "Centre", "Champagne-Ardenne", 
        "Corse", "Franche-Comté", "Haute-Normandie", "Île-de-France", "Languedoc-Roussillon", "Limousin", "Lorraine", 
        "Midi-Pyrénées", "Nord-Pas-de-Calais", "Pays de la Loire", "Picardie", "Poitou-Charentes", "Provence-Alpes-Côte d'Azur", 
        "Rhône-Alpes"
    ]
    
    # Associer aléatoirement un territoire à chaque ID du contact unique
    territoire_par_id = {id_contact: random.choice(territoires) for id_contact in unique_ids}
    
    # Appliquer les attributions de territoire au DataFrame
    data['Territoire Terre de Liens'] = data['ID du contact'].map(territoire_par_id)
    # Afficher les premières lignes du DataFrame pour vérification
    
    
    # Générer aléatoirement des valeurs 0 ou 1 pour chaque ID du contact unique
    valeurs_adherent_n_1 = np.random.randint(0, 2, size=len(unique_ids))
    valeurs_adherent_n = np.random.randint(0, 2, size=len(unique_ids))
    valeurs_donateur_n = np.random.randint(0, 2, size=len(unique_ids))
    
    # Créer des dictionnaires pour associer chaque ID du contact à ses valeurs respectives
    adherent_n_1_par_id = dict(zip(unique_ids, valeurs_adherent_n_1))
    adherent_n_par_id = dict(zip(unique_ids, valeurs_adherent_n))
    donateur_n_par_id = dict(zip(unique_ids, valeurs_donateur_n))
    
    # Appliquer les valeurs correspondantes aux colonnes du DataFrame
    data['adhérent N-1'] = data['ID du contact'].map(adherent_n_1_par_id)
    data['adhérent N'] = data['ID du contact'].map(adherent_n_par_id)
    data['Donateur N'] = data['ID du contact'].map(donateur_n_par_id)
    
    # Définition de la fonction pour générer une date aléatoire entre deux dates données
    def random_date(start_date, end_date):
        return start_date + timedelta(
            days=random.randint(0, (end_date - start_date).days)
        )
    
    
    # Générer des dates aléatoires pour 'RFM-Date Première Souscription' entre le 01/02/2006 et le 31/07/2022
    start_date = datetime(2006, 2, 1)
    end_date = datetime(2022, 7, 31)
    
    # Créer un dictionnaire pour associer chaque ID du contact à une date 'RFM-Date Première Souscription' unique
    rfm_dates = {id_contact: random_date(start_date, end_date) for id_contact in unique_ids}
    
    # Appliquer les dates correspondantes aux ID du contact dans le DataFrame original
    data['RFM-Date Première Souscription'] = data['ID du contact'].map(rfm_dates)
    
    
    # Créez un dictionnaire pour stocker les dates du dernier don par ID du contact
    rfm_date_dernier_don_par_id = {}
    this_year = datetime.now().year
    
    # Générez des dates aléatoires pour 'RFM-Date Dernier Don' en fonction de la valeur 'Donateur N'
    for id_contact in unique_ids:
        if donateur_n_par_id[id_contact] == 1:
            # Si Donateur N est égal à 1, générez une date entre le 01/01 de cette année et le 31/12 de cette année
            this_year = datetime.now().year
            rfm_date_dernier_don_par_id[id_contact] = random_date(datetime(this_year, 1, 1), datetime(this_year, 12, 31))
        else:
            # Sinon, générez une date entre le 01/01/2006 et le 01/01 de cette année (exclu)
            rfm_date_dernier_don_par_id[id_contact] = random_date(datetime(2006, 1, 1), datetime(this_year, 1, 1))
    
    # Appliquez les dates du dernier don correspondantes aux ID du contact dans le DataFrame original
    data['RFM-Date Dernier Don'] = data['ID du contact'].map(rfm_date_dernier_don_par_id)
    
    
    # Créer une liste de nombres avec des probabilités
    # Plus de probabilité d'obtenir un nombre entre 1 et 10, moins de probabilité pour 0, et très rarement pour 10 à 8000
    nombres_actions_detenues = []
    for _ in range(len(unique_ids)):
        random_value = random.random()
        if random_value < 0.7:  # 70% de chance d'obtenir un nombre entre 1 et 10
            nombre = random.randint(1, 100)
        elif random_value < 0.85:  # 15% de chance d'obtenir un zéro
            nombre = 0
        else:  # 15% de chance d'obtenir un nombre entre 10 et 8000
            nombre = random.randint(101, 8000)
        nombres_actions_detenues.append(nombre)
    
    # Créer un dictionnaire pour associer chaque ID du contact à son nombre d'actions
    id_to_actions_detenues = dict(zip(unique_ids, nombres_actions_detenues))
    
    # Appliquer le nombre d'actions correspondant à chaque ID du contact dans le DataFrame original
    data['Foncière : Nombre d\'actions détenues'] = data['ID du contact'].map(id_to_actions_detenues)
    data["Foncière : Capital possédé"] = data['Foncière : Nombre d\'actions détenues'] * 105
    data['Actionnaire ?'] = data['Foncière : Nombre d\'actions détenues'].apply(lambda x: 0 if x == 0 else 1)
    
    nouvel_ordre = [
        'Nom complet', 'ID du contact', 'âge', 'Territoire Terre de Liens', 'Actionnaire ?',
        'adhérent N-1', 'adhérent N', 'Donateur N', 'RFM-Date Première Souscription',
        'RFM-Date Dernier Don', 'Foncière : Capital possédé', 'Foncière : Nombre d\'actions détenues'
    ]
    
    data = data[nouvel_ordre]
    somme_capital = data.drop_duplicates(subset = "ID du contact")
    somme_capital = somme_capital['Foncière : Capital possédé'].sum()
    data["Foncière : Part du capital possédée (%)"] = data['Foncière : Capital possédé']/somme_capital *100
    data['Numéro du contrat'] = ['{:06}'.format(random.randint(0, 999999)) for _ in range(len(data))]
    data["Type d'enregistrement des contrats"] = "Foncière - Action PP"
    # Fonction pour générer le nombre d'actions à l'acquisition en fonction des probabilités
    def generate_nombre_actions():
        random_value = random.random()
        if random_value < 0.50:  # 30% des cas : de 0 à 10 actions
            return random.randint(1, 10)
        elif random_value < 0.75:  # 30% des cas : de 10 à 50 actions
            return random.randint(10, 50)
        elif random_value < 0.90:  # 30% des cas : de 50 à 100 actions
            return random.randint(50, 100)
        else:  # 10% des cas : de 100 à 500 actions
            return random.randint(100, 500)
    
    # Appliquez la fonction pour générer le nombre d'actions à l'acquisition pour chaque ligne
    data['Nombre d\'actions à l\'acquisition'] = [generate_nombre_actions() for _ in range(len(data))]
    
    # Fonction pour générer la valeur de "A fait l'objet d'un reçu fiscal" en fonction de la probabilité
    def generate_recu_fiscal():
        random_value = random.random()
        if random_value < 0.7688:  # 76,88% de chance d'obtenir 1
            return 1
        else:
            return 0
    
    # Appliquez la fonction pour générer la valeur de "A fait l'objet d'un reçu fiscal" pour chaque ligne
    data["A fait l'objet d'un reçu fiscal"] = [generate_recu_fiscal() for _ in range(len(data))]
    
    # Fonction pour générer la valeur de "Affectation" en fonction des proportions spécifiées
    def generate_affectation():
        random_value = random.random()
        if random_value < 1/3:  # 1/3 des cas, "Ensemble des fermes de la Foncière"
            return "Ensemble des fermes de la Foncière"
        elif random_value < 2/3:  # 1/3 des cas, "Collecte dédiée" + valeur aléatoire dans "territoires"
            territoires = [
                "Alsace", "Aquitaine", "Auvergne", "Basse-Normandie", "Bourgogne", "Bretagne", "Centre", "Champagne-Ardenne", 
                "Corse", "Franche-Comté", "Haute-Normandie", "Île-de-France", "Languedoc-Roussillon", "Limousin", "Lorraine", 
                "Midi-Pyrénées", "Nord-Pas-de-Calais", "Pays de la Loire", "Picardie", "Poitou-Charentes", "Provence-Alpes-Côte d'Azur", 
                "Rhône-Alpes"
            ]
            random_territoire = random.choice(territoires)
            return f"Collecte dédiée - {random_territoire}"
        else:  # 1/3 des cas, combinaison de 6 lettres aléatoires
            lettres = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
            return ''.join(random.choice(lettres) for _ in range(6))
    
    # Appliquez la fonction pour générer la valeur de "Affectation" pour chaque ligne
    data["Affectation"] = [generate_affectation() for _ in range(len(data))]
    
    
    # Fonction pour générer une combinaison de 6 chiffres aléatoires
    def generer_combinaison_chiffres():
        chiffres = '0123456789'
        return ''.join(random.choice(chiffres) for _ in range(6))
    
    # Appliquez la fonction pour générer les valeurs de la colonne "M-XXXXXX"
    data["Mouvement de titre Name"] = ["M-" + generer_combinaison_chiffres() for _ in range(len(data))]
    
    # Définissez les valeurs possibles pour la colonne "Nature du mouvement"
    valeurs_possibles = ['Souscription'] * 80 + ['Don TDL'] * 7 + ['Rachat'] * 13
    
    # Utilisez numpy.random.choice pour attribuer ces valeurs en fonction des pourcentages
    data["Nature du mouvement"] = np.random.choice(valeurs_possibles, size=len(data))
    
    # Fonction pour générer des dates aléatoires entre le 01/01/2006 et aujourd'hui
    def generate_date_activation():
        start_date = datetime(2006, 1, 1)
        end_date = datetime.now()
        random_date = start_date + timedelta(days=random.randint(0, (end_date - start_date).days))
        return random_date
    
    # Appliquer la fonction pour créer la colonne "Date d'activation"
    data['Date d\'activation'] = [generate_date_activation() for _ in range(len(data))]
    # Générez des dates aléatoires pour chaque ligne en fonction de "RFM-Date Première Souscription"
    random_dates = []
    for _, row in data.iterrows():
        start_date = row['RFM-Date Première Souscription']
        end_date = datetime(2023, 7, 31)
        random_date = start_date + timedelta(days=np.random.randint(0, (end_date - start_date).days))
        random_dates.append(random_date)
    
    # Ajoutez la colonne "Date du Mouvement" au DataFrame
    data['Date du Mouvement'] = random_dates
    
    
    # Fonction pour générer "Nombre d'actions échangées" en fonction de "Nature du mouvement"
    def generate_actions_echangees(row):
        if row['Nature du mouvement'] == 'Souscription':
            return row['Nombre d\'actions à l\'acquisition']
        else:
            # Vérifiez d'abord que "Nombre d'actions à l'acquisition" est supérieur à zéro
            if row['Nombre d\'actions à l\'acquisition'] > 0:
                # 80% de chance que "Nombre d'actions échangées" soit égal à "Nombre d'actions à l'acquisition"
                # 20% de chance que "Nombre d'actions échangées" soit strictement inférieur à "Nombre d'actions à l'acquisition"
                if np.random.rand() < 0.8:
                    return row['Nombre d\'actions à l\'acquisition']
                else:
                    return np.random.randint(1, row['Nombre d\'actions à l\'acquisition'] + 1)
            else:
                return 0  # Si "Nombre d'actions à l'acquisition" est zéro, "Nombre d'actions échangées" est également zéro
    
    # Appliquez la fonction pour créer la colonne "Nombre d'actions échangées"
    data['Nombre d\'actions échangées'] = data.apply(generate_actions_echangees, axis=1)
    
    # Fonction pour générer "Actions - Date de fin" en fonction des conditions
    def generate_actions_date_fin(row):
        if row['Nature du mouvement'] == 'Souscription':
            # Si "Nature du mouvement" est "Souscription"
            if random.random() < 0.5:
                return datetime.now()  # 90% des cas, aujourd'hui
            else:
                return row['Date du Mouvement'] + timedelta(days=random.randint(1, (datetime.now() - row['Date du Mouvement']).days - 1))
        elif (row['Nature du mouvement'] == 'Don TDL' or row['Nature du mouvement'] == 'Rachat') and row['Nombre d\'actions à l\'acquisition'] == row['Nombre d\'actions échangées']:
            # Si "Nature du mouvement" est "Don TDL" ou "Rachat" et "Nombre d'actions à l'acquisition" est égal à "Nombre d'actions échangées"
            return row['Date du Mouvement']
        elif (row['Nature du mouvement'] == 'Don TDL' or row['Nature du mouvement'] == 'Rachat') and row['Nombre d\'actions à l\'acquisition'] > row['Nombre d\'actions échangées']:
            # Si "Nature du mouvement" est "Don TDL" ou "Rachat" et "Nombre d'actions à l'acquisition" est supérieur à "Nombre d'actions échangées"
            if random.random() < 0.9:
                return datetime.now()  # 90% des cas, aujourd'hui
            else:
                return row['Date du Mouvement'] + timedelta(days=random.randint(1, (datetime.now() - row['Date du Mouvement']).days - 1))
    
    
    # Appliquez la fonction pour créer la colonne "Actions - Date de fin"
    data['Actions - Date de fin'] = data.apply(generate_actions_date_fin, axis=1)
    
    import random import pandas as pd import string import numpy as np from datetime import datetime, timedelta # Fonction pour générer une combinaison de 6 lettres aléatoires def generer_combinaison(): lettres = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' return ''.join(random.choice(lettres) for _ in range(6)) # Générer une liste de 20 000 combinaisons de noms complets uniques noms_complets = set() while len(noms_complets) < 20000: nom_complet = f"{generer_combinaison()} {generer_combinaison()}" noms_complets.add(nom_complet) # Répéter aléatoirement les noms complets jusqu'à 12 fois maximum noms_complets_repetes = [] for nom_complet in noms_complets: repetitions = random.randint(0, 12) noms_complets_repetes.extend([nom_complet] * repetitions) # Limiter la liste à 20 000 éléments noms_complets_final = random.sample(noms_complets_repetes, 20000) # Créer un DataFrame pandas avec les noms complets data = pd.DataFrame({'Nom complet': noms_complets_final}) # Fonction pour générer une combinaison de 6 lettres aléatoires def generer_combinaison(): lettres = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' return ''.join(random.choice(lettres) for _ in range(6)) # Générer une liste de 35 combinaisons de noms complets uniques répétées 11 fois noms_complets_35 = [] for _ in range(35): nom_complet = f"{generer_combinaison()} {generer_combinaison()}" noms_complets_35.extend([nom_complet] * 11) # Générer une liste de 65 combinaisons de noms complets uniques répétées 12 fois noms_complets_65 = [] for _ in range(65): nom_complet = f"{generer_combinaison()} {generer_combinaison()}" noms_complets_65.extend([nom_complet] * 12) # Combiner les deux listes noms_complets_final = noms_complets_35 + noms_complets_65 # Créer un DataFrame pandas avec les noms complets data2 = pd.DataFrame({'Nom complet': noms_complets_final}) # Concaténer les deux DataFrames data = pd.concat([data, data2], ignore_index=True) # Initialiser un dictionnaire pour suivre les ID du contact par nom complet id_du_contact_par_nom = {} # Générer une liste de noms complets avec répétition noms_complets = data['Nom complet'] # Générer une liste d'ID de contact basée sur les noms complets (mêmes noms auront les mêmes ID) ids_contacts = [''.join(random.choices(string.ascii_uppercase + string.digits, k=10)) + ''.join(random.choices(string.ascii_uppercase, k=2)) for _ in range(21165)] # Remplir le dictionnaire ID du contact par nom complet for nom_complet, id_contact in zip(noms_complets, ids_contacts): if nom_complet not in id_du_contact_par_nom: id_du_contact_par_nom[nom_complet] = id_contact # Utiliser le dictionnaire pour obtenir les ID du contact pour chaque nom complet data['ID du contact'] = [id_du_contact_par_nom[nom_complet] for nom_complet in noms_complets] # Créer une colonne 'âge' en attribuant un âge aléatoire entre 0 et 90 à chaque ID du contact unique unique_ids = data['ID du contact'].unique() ages = [random.randint(0, 90) for _ in range(len(unique_ids))] # Créer un dictionnaire pour associer chaque ID du contact à son âge id_to_age = dict(zip(unique_ids, ages)) # Appliquer l'âge correspondant à chaque ID du contact dans le DataFrame original data['âge'] = data['ID du contact'].map(id_to_age) territoires = [ "Alsace", "Aquitaine", "Auvergne", "Basse-Normandie", "Bourgogne", "Bretagne", "Centre", "Champagne-Ardenne", "Corse", "Franche-Comté", "Haute-Normandie", "Île-de-France", "Languedoc-Roussillon", "Limousin", "Lorraine", "Midi-Pyrénées", "Nord-Pas-de-Calais", "Pays de la Loire", "Picardie", "Poitou-Charentes", "Provence-Alpes-Côte d'Azur", "Rhône-Alpes" ] # Associer aléatoirement un territoire à chaque ID du contact unique territoire_par_id = {id_contact: random.choice(territoires) for id_contact in unique_ids} # Appliquer les attributions de territoire au DataFrame data['Territoire Terre de Liens'] = data['ID du contact'].map(territoire_par_id) # Afficher les premières lignes du DataFrame pour vérification # Générer aléatoirement des valeurs 0 ou 1 pour chaque ID du contact unique valeurs_adherent_n_1 = np.random.randint(0, 2, size=len(unique_ids)) valeurs_adherent_n = np.random.randint(0, 2, size=len(unique_ids)) valeurs_donateur_n = np.random.randint(0, 2, size=len(unique_ids)) # Créer des dictionnaires pour associer chaque ID du contact à ses valeurs respectives adherent_n_1_par_id = dict(zip(unique_ids, valeurs_adherent_n_1)) adherent_n_par_id = dict(zip(unique_ids, valeurs_adherent_n)) donateur_n_par_id = dict(zip(unique_ids, valeurs_donateur_n)) # Appliquer les valeurs correspondantes aux colonnes du DataFrame data['adhérent N-1'] = data['ID du contact'].map(adherent_n_1_par_id) data['adhérent N'] = data['ID du contact'].map(adherent_n_par_id) data['Donateur N'] = data['ID du contact'].map(donateur_n_par_id) # Définition de la fonction pour générer une date aléatoire entre deux dates données def random_date(start_date, end_date): return start_date + timedelta( days=random.randint(0, (end_date - start_date).days) ) # Générer des dates aléatoires pour 'RFM-Date Première Souscription' entre le 01/02/2006 et le 31/07/2022 start_date = datetime(2006, 2, 1) end_date = datetime(2022, 7, 31) # Créer un dictionnaire pour associer chaque ID du contact à une date 'RFM-Date Première Souscription' unique rfm_dates = {id_contact: random_date(start_date, end_date) for id_contact in unique_ids} # Appliquer les dates correspondantes aux ID du contact dans le DataFrame original data['RFM-Date Première Souscription'] = data['ID du contact'].map(rfm_dates) # Créez un dictionnaire pour stocker les dates du dernier don par ID du contact rfm_date_dernier_don_par_id = {} this_year = datetime.now().year # Générez des dates aléatoires pour 'RFM-Date Dernier Don' en fonction de la valeur 'Donateur N' for id_contact in unique_ids: if donateur_n_par_id[id_contact] == 1: # Si Donateur N est égal à 1, générez une date entre le 01/01 de cette année et le 31/12 de cette année this_year = datetime.now().year rfm_date_dernier_don_par_id[id_contact] = random_date(datetime(this_year, 1, 1), datetime(this_year, 12, 31)) else: # Sinon, générez une date entre le 01/01/2006 et le 01/01 de cette année (exclu) rfm_date_dernier_don_par_id[id_contact] = random_date(datetime(2006, 1, 1), datetime(this_year, 1, 1)) # Appliquez les dates du dernier don correspondantes aux ID du contact dans le DataFrame original data['RFM-Date Dernier Don'] = data['ID du contact'].map(rfm_date_dernier_don_par_id) # Créer une liste de nombres avec des probabilités # Plus de probabilité d'obtenir un nombre entre 1 et 10, moins de probabilité pour 0, et très rarement pour 10 à 8000 nombres_actions_detenues = [] for _ in range(len(unique_ids)): random_value = random.random() if random_value < 0.7: # 70% de chance d'obtenir un nombre entre 1 et 10 nombre = random.randint(1, 100) elif random_value < 0.85: # 15% de chance d'obtenir un zéro nombre = 0 else: # 15% de chance d'obtenir un nombre entre 10 et 8000 nombre = random.randint(101, 8000) nombres_actions_detenues.append(nombre) # Créer un dictionnaire pour associer chaque ID du contact à son nombre d'actions id_to_actions_detenues = dict(zip(unique_ids, nombres_actions_detenues)) # Appliquer le nombre d'actions correspondant à chaque ID du contact dans le DataFrame original data['Foncière : Nombre d\'actions détenues'] = data['ID du contact'].map(id_to_actions_detenues) data["Foncière : Capital possédé"] = data['Foncière : Nombre d\'actions détenues'] * 105 data['Actionnaire ?'] = data['Foncière : Nombre d\'actions détenues'].apply(lambda x: 0 if x == 0 else 1) nouvel_ordre = [ 'Nom complet', 'ID du contact', 'âge', 'Territoire Terre de Liens', 'Actionnaire ?', 'adhérent N-1', 'adhérent N', 'Donateur N', 'RFM-Date Première Souscription', 'RFM-Date Dernier Don', 'Foncière : Capital possédé', 'Foncière : Nombre d\'actions détenues' ] data = data[nouvel_ordre] somme_capital = data.drop_duplicates(subset = "ID du contact") somme_capital = somme_capital['Foncière : Capital possédé'].sum() data["Foncière : Part du capital possédée (%)"] = data['Foncière : Capital possédé']/somme_capital *100 data['Numéro du contrat'] = ['{:06}'.format(random.randint(0, 999999)) for _ in range(len(data))] data["Type d'enregistrement des contrats"] = "Foncière - Action PP" # Fonction pour générer le nombre d'actions à l'acquisition en fonction des probabilités def generate_nombre_actions(): random_value = random.random() if random_value < 0.50: # 30% des cas : de 0 à 10 actions return random.randint(1, 10) elif random_value < 0.75: # 30% des cas : de 10 à 50 actions return random.randint(10, 50) elif random_value < 0.90: # 30% des cas : de 50 à 100 actions return random.randint(50, 100) else: # 10% des cas : de 100 à 500 actions return random.randint(100, 500) # Appliquez la fonction pour générer le nombre d'actions à l'acquisition pour chaque ligne data['Nombre d\'actions à l\'acquisition'] = [generate_nombre_actions() for _ in range(len(data))] # Fonction pour générer la valeur de "A fait l'objet d'un reçu fiscal" en fonction de la probabilité def generate_recu_fiscal(): random_value = random.random() if random_value < 0.7688: # 76,88% de chance d'obtenir 1 return 1 else: return 0 # Appliquez la fonction pour générer la valeur de "A fait l'objet d'un reçu fiscal" pour chaque ligne data["A fait l'objet d'un reçu fiscal"] = [generate_recu_fiscal() for _ in range(len(data))] # Fonction pour générer la valeur de "Affectation" en fonction des proportions spécifiées def generate_affectation(): random_value = random.random() if random_value < 1/3: # 1/3 des cas, "Ensemble des fermes de la Foncière" return "Ensemble des fermes de la Foncière" elif random_value < 2/3: # 1/3 des cas, "Collecte dédiée" + valeur aléatoire dans "territoires" territoires = [ "Alsace", "Aquitaine", "Auvergne", "Basse-Normandie", "Bourgogne", "Bretagne", "Centre", "Champagne-Ardenne", "Corse", "Franche-Comté", "Haute-Normandie", "Île-de-France", "Languedoc-Roussillon", "Limousin", "Lorraine", "Midi-Pyrénées", "Nord-Pas-de-Calais", "Pays de la Loire", "Picardie", "Poitou-Charentes", "Provence-Alpes-Côte d'Azur", "Rhône-Alpes" ] random_territoire = random.choice(territoires) return f"Collecte dédiée - {random_territoire}" else: # 1/3 des cas, combinaison de 6 lettres aléatoires lettres = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' return ''.join(random.choice(lettres) for _ in range(6)) # Appliquez la fonction pour générer la valeur de "Affectation" pour chaque ligne data["Affectation"] = [generate_affectation() for _ in range(len(data))] # Fonction pour générer une combinaison de 6 chiffres aléatoires def generer_combinaison_chiffres(): chiffres = '0123456789' return ''.join(random.choice(chiffres) for _ in range(6)) # Appliquez la fonction pour générer les valeurs de la colonne "M-XXXXXX" data["Mouvement de titre Name"] = ["M-" + generer_combinaison_chiffres() for _ in range(len(data))] # Définissez les valeurs possibles pour la colonne "Nature du mouvement" valeurs_possibles = ['Souscription'] * 80 + ['Don TDL'] * 7 + ['Rachat'] * 13 # Utilisez numpy.random.choice pour attribuer ces valeurs en fonction des pourcentages data["Nature du mouvement"] = np.random.choice(valeurs_possibles, size=len(data)) # Fonction pour générer des dates aléatoires entre le 01/01/2006 et aujourd'hui def generate_date_activation(): start_date = datetime(2006, 1, 1) end_date = datetime.now() random_date = start_date + timedelta(days=random.randint(0, (end_date - start_date).days)) return random_date # Appliquer la fonction pour créer la colonne "Date d'activation" data['Date d\'activation'] = [generate_date_activation() for _ in range(len(data))] # Générez des dates aléatoires pour chaque ligne en fonction de "RFM-Date Première Souscription" random_dates = [] for _, row in data.iterrows(): start_date = row['RFM-Date Première Souscription'] end_date = datetime(2023, 7, 31) random_date = start_date + timedelta(days=np.random.randint(0, (end_date - start_date).days)) random_dates.append(random_date) # Ajoutez la colonne "Date du Mouvement" au DataFrame data['Date du Mouvement'] = random_dates # Fonction pour générer "Nombre d'actions échangées" en fonction de "Nature du mouvement" def generate_actions_echangees(row): if row['Nature du mouvement'] == 'Souscription': return row['Nombre d\'actions à l\'acquisition'] else: # Vérifiez d'abord que "Nombre d'actions à l'acquisition" est supérieur à zéro if row['Nombre d\'actions à l\'acquisition'] > 0: # 80% de chance que "Nombre d'actions échangées" soit égal à "Nombre d'actions à l'acquisition" # 20% de chance que "Nombre d'actions échangées" soit strictement inférieur à "Nombre d'actions à l'acquisition" if np.random.rand() < 0.8: return row['Nombre d\'actions à l\'acquisition'] else: return np.random.randint(1, row['Nombre d\'actions à l\'acquisition'] + 1) else: return 0 # Si "Nombre d'actions à l'acquisition" est zéro, "Nombre d'actions échangées" est également zéro # Appliquez la fonction pour créer la colonne "Nombre d'actions échangées" data['Nombre d\'actions échangées'] = data.apply(generate_actions_echangees, axis=1) # Fonction pour générer "Actions - Date de fin" en fonction des conditions def generate_actions_date_fin(row): if row['Nature du mouvement'] == 'Souscription': # Si "Nature du mouvement" est "Souscription" if random.random() < 0.5: return datetime.now() # 90% des cas, aujourd'hui else: return row['Date du Mouvement'] + timedelta(days=random.randint(1, (datetime.now() - row['Date du Mouvement']).days - 1)) elif (row['Nature du mouvement'] == 'Don TDL' or row['Nature du mouvement'] == 'Rachat') and row['Nombre d\'actions à l\'acquisition'] == row['Nombre d\'actions échangées']: # Si "Nature du mouvement" est "Don TDL" ou "Rachat" et "Nombre d'actions à l'acquisition" est égal à "Nombre d'actions échangées" return row['Date du Mouvement'] elif (row['Nature du mouvement'] == 'Don TDL' or row['Nature du mouvement'] == 'Rachat') and row['Nombre d\'actions à l\'acquisition'] > row['Nombre d\'actions échangées']: # Si "Nature du mouvement" est "Don TDL" ou "Rachat" et "Nombre d'actions à l'acquisition" est supérieur à "Nombre d'actions échangées" if random.random() < 0.9: return datetime.now() # 90% des cas, aujourd'hui else: return row['Date du Mouvement'] + timedelta(days=random.randint(1, (datetime.now() - row['Date du Mouvement']).days - 1)) # Appliquez la fonction pour créer la colonne "Actions - Date de fin" data['Actions - Date de fin'] = data.apply(generate_actions_date_fin, axis=1)
    In [5]:
    Copied!
    import pandas as pd
    import numpy as np
    from datetime import datetime, timedelta
    import warnings
    warnings.filterwarnings("ignore")
    df = data
    df_var_tps_reprise = df.copy()
    df_partrachat = df.copy()
    df_fidèle = df.copy()
    df_doublon = df.copy()
    df_serie_sous = df.copy()
    df_serie_sousbis = df.copy()
    dfretraitrepise = df.copy()
    df_parcoursD = df.copy()
    df_MS_infos = df.copy()
    df_info_parcours = df.copy()
    df_parcours =df.copy()
    dfsousmoy = df.copy()
    df_parcoursD = df.copy()
    df_MS_infos = df.copy()
    df_info_parcours = df.copy()
    df_parcours =df.copy()
    dfsousmoy = df.copy()
    
    import pandas as pd import numpy as np from datetime import datetime, timedelta import warnings warnings.filterwarnings("ignore") df = data df_var_tps_reprise = df.copy() df_partrachat = df.copy() df_fidèle = df.copy() df_doublon = df.copy() df_serie_sous = df.copy() df_serie_sousbis = df.copy() dfretraitrepise = df.copy() df_parcoursD = df.copy() df_MS_infos = df.copy() df_info_parcours = df.copy() df_parcours =df.copy() dfsousmoy = df.copy() df_parcoursD = df.copy() df_MS_infos = df.copy() df_info_parcours = df.copy() df_parcours =df.copy() dfsousmoy = df.copy()
    In [6]:
    Copied!
    df_parcours1 = df_parcours[df_parcours["Nature du mouvement"] == "Souscription"]
    df_parcours1['Année souscription'] = 'souscription_en_' + df_parcours1['Date du Mouvement'].dt.year.astype(str)
    df_parcours1 = df_parcours1.sort_values(by=['ID du contact', "Date du Mouvement"])
    df_parcours1 = df_parcours1[["Nom complet","ID du contact", "Année souscription","Nombre d'actions à l'acquisition"]]
    df_parcours1 = df_parcours1.pivot_table(index=['Nom complet','ID du contact'], columns='Année souscription', values='Nombre d\'actions à l\'acquisition', aggfunc='sum')
    df_parcours2 = df_parcours[df_parcours["Nature du mouvement"] == "Rachat"]
    df_parcours2['Année rachat'] = 'Rachat_en_' + df_parcours2['Date du Mouvement'].dt.year.astype(str)
    df_parcours2 = df_parcours2.sort_values(by=['ID du contact', "Date du Mouvement"])
    df_parcours2 = df_parcours2[["Nom complet","ID du contact", "Année rachat","Nombre d'actions échangées"]]
    df_parcours2 = df_parcours2.pivot_table(index=['Nom complet','ID du contact'], columns='Année rachat', values='Nombre d\'actions échangées', aggfunc='sum')
    df_parcours1 = df_parcours1.reset_index()
    df_parcours2 = df_parcours2.reset_index()
    df_parcours = df_parcours1.merge(df_parcours2, on=['Nom complet', 'ID du contact'], how='left')
    conditions = [
        (df_info_parcours['âge'] < 25),
        (df_info_parcours['âge'] < 40),
        (df_info_parcours['âge'] < 60)
    ]
    
    choices = ['0-25 ans', '25-40 ans', '40-60 ans']
    
    df_info_parcours['catégories âge'] = np.select(conditions, choices, default='60 ans et plus')
    df_info_parcours['RFM-Date Première Souscription'] = pd.to_datetime(df_info_parcours['RFM-Date Première Souscription'], dayfirst=True)
    
    conditions = [
         (df_info_parcours['RFM-Date Première Souscription'] <= pd.to_datetime('2012')),
         (df_info_parcours['RFM-Date Première Souscription'] <= pd.to_datetime('2017'))
    ]
    
    choices = ['Nouvel actionnaire en 2012 ou moins', 'Nouvel actionnaire entre 2012 à 2017']
    
    df_info_parcours['ancienneté actionnaires'] = np.select(conditions, choices, default='Nouvel actionnaire depuis 2017 ou plus')
    df_info_parcours['RFM-Date Première Souscription'] = pd.to_datetime(df_info_parcours['RFM-Date Première Souscription'], format='%d/%m/%Y')
    df_info_parcours['répartition année nouveau actionnaire'] = df_info_parcours['RFM-Date Première Souscription'].dt.year
    twenty4_months_ago = datetime.now() - timedelta(days=730)
    df_info_parcours['RFM-Date Dernier Don'] = pd.to_datetime(df_info_parcours['RFM-Date Dernier Don'], format='%d/%m/%Y')
    
    df_info_parcours.loc[:, "multi-casquette ?"] = df_info_parcours.apply(lambda row: "Actionnaire-donateur" if row["Actionnaire ?"] == 1 and (row["Donateur N"] == 1 or row['RFM-Date Dernier Don'] >= twenty4_months_ago)  and row["adhérent N"] == 0 and row['adhérent N-1'] == 0
                                                else "Actionnaire-adhérent" if row["Actionnaire ?"] == 1 and (row["adhérent N"] == 1 or row['adhérent N-1'] == 1) and row["Donateur N"] == 0 and row['RFM-Date Dernier Don'] < twenty4_months_ago
                                                else "Triple-engagement" if row["Actionnaire ?"] == 1 and (row["adhérent N"] == 1 or row['adhérent N-1'] == 1) and (row["Donateur N"] == 1 or row['RFM-Date Dernier Don'] >= twenty4_months_ago)
                                                else "Plus actionnaire" if row["Actionnaire ?"] == 0 
                                                else "Actionaire uniquement", axis=1)
    colonnes_suppr = [
        'Type d\'enregistrement des contrats',
           'Nombre d\'actions à l\'acquisition', 'A fait l\'objet d\'un reçu fiscal',
           'Affectation', 'Mouvement de titre Name', 'Nature du mouvement',
           'Date d\'activation', 'Date du Mouvement', 'Actions - Date de fin',
           'Nombre d\'actions échangées'
    ]
    df_info_parcours = df_info_parcours.drop_duplicates(subset="ID du contact")
    df_info_parcours = df_info_parcours.drop(columns=colonnes_suppr)
    df_MS_infos = df_MS_infos[(df_MS_infos["Nature du mouvement"] == "Souscription") | (df_MS_infos["Nature du mouvement"] == "Rachat")]
    df_MS_infos = df_MS_infos.sort_values(by = ["ID du contact", "Nature du mouvement", "Date du Mouvement"])
    df_MS_infos = df_MS_infos[["Nom complet","ID du contact","Nature du mouvement"]]
    df_MS_infos = df_MS_infos.groupby(["ID du contact", "Nature du mouvement"]).size().reset_index(name='Nombre de SS et de rachats')
    df_MS_infos = df_MS_infos.pivot_table(index=['ID du contact'], columns='Nature du mouvement', values='Nombre de SS et de rachats', aggfunc='sum')
    df_info_parcours = df_info_parcours.merge(df_MS_infos, on=[ 'ID du contact'], how='left')
    df_info_parcours = df_info_parcours.rename(columns={'Rachat': 'Nombre de rachats'})
    df_info_parcours = df_info_parcours.rename(columns={'Souscription': 'Nombre de souscriptions'})
    df_parcours = df_parcours.merge(df_info_parcours, on=["Nom complet",'ID du contact'], how='left')
    df_parcours['multi-souscripteur ?'] = df_parcours['Nombre de souscriptions'].apply(lambda x: x > 1)
    dfsousmoy = dfsousmoy[dfsousmoy["Nature du mouvement"] == "Souscription"]
    dfsousmoy['Nombre de souscriptions'] = dfsousmoy['ID du contact'].map(df['ID du contact'].value_counts())
    dfsousmoy = dfsousmoy[["ID du contact", 'Nombre de souscriptions', "Nombre d'actions à l'acquisition"]]
    dfsousmoy = dfsousmoy.groupby('ID du contact').agg({'Nombre de souscriptions': 'first', 'Nombre d\'actions à l\'acquisition': 'sum'}).reset_index()
    dfsousmoy["Nombre moyen d'actions par souscription"] = dfsousmoy["Nombre d'actions à l'acquisition"]/dfsousmoy["Nombre de souscriptions"]
    dfsousmoy = dfsousmoy[["ID du contact", "Nombre moyen d'actions par souscription"]]
    df_parcours = df_parcours.merge(dfsousmoy, on=['ID du contact'], how='left')
    df_parcoursD = df_parcoursD[df_parcoursD["Actionnaire ?"] == True]
    df_parcoursD = df_parcoursD.drop_duplicates(subset = "ID du contact")
    df_parcoursD = df_parcoursD[["ID du contact","Foncière : Nombre d'actions détenues"]]
    # Calculer les déciles avec des intervalles égaux
    deciles = pd.qcut(df_parcoursD["Foncière : Nombre d'actions détenues"], q=11, duplicates='drop')
    # En utilisant duplicates='drop'  la fonction supprimera les bornes en double. Cela signifie que si deux valeurs identiques tombent exactement sur une limite d'intervalle, l'une des bornes sera supprimée, de sorte que chaque limite d'intervalle est unique. Cela peut entraîner un nombre réduit d'intervalles si vos données ont beaucoup de valeurs identiques.Il faut donc prévoir des intervalles en plus pour en spécifier 10  soit utiliser q = 11 au lieu de 10 
    # Utilisez ces intervalles pour découper les déciles
    df_parcoursD['déciles actionnaire'] = deciles
    df_parcoursD['déciles actionnaire'] = df_parcoursD['déciles actionnaire'].cat.codes + 1
    
    # Créer une nouvelle colonne avec la catégorie d1 à d10
    df_parcoursD['Déciles actionnaires'] = 'Décile ' + df_parcoursD['déciles actionnaire'].astype(str)
    df_parcoursD = df_parcoursD[["ID du contact","Déciles actionnaires"]]
    df_parcours = df_parcours.merge(df_parcoursD, on=['ID du contact'], how='left')
    df_parcours['Déciles actionnaires'] = df_parcours['Déciles actionnaires'].fillna('plus actionnaire')
    
    df_parcours1 = df_parcours[df_parcours["Nature du mouvement"] == "Souscription"] df_parcours1['Année souscription'] = 'souscription_en_' + df_parcours1['Date du Mouvement'].dt.year.astype(str) df_parcours1 = df_parcours1.sort_values(by=['ID du contact', "Date du Mouvement"]) df_parcours1 = df_parcours1[["Nom complet","ID du contact", "Année souscription","Nombre d'actions à l'acquisition"]] df_parcours1 = df_parcours1.pivot_table(index=['Nom complet','ID du contact'], columns='Année souscription', values='Nombre d\'actions à l\'acquisition', aggfunc='sum') df_parcours2 = df_parcours[df_parcours["Nature du mouvement"] == "Rachat"] df_parcours2['Année rachat'] = 'Rachat_en_' + df_parcours2['Date du Mouvement'].dt.year.astype(str) df_parcours2 = df_parcours2.sort_values(by=['ID du contact', "Date du Mouvement"]) df_parcours2 = df_parcours2[["Nom complet","ID du contact", "Année rachat","Nombre d'actions échangées"]] df_parcours2 = df_parcours2.pivot_table(index=['Nom complet','ID du contact'], columns='Année rachat', values='Nombre d\'actions échangées', aggfunc='sum') df_parcours1 = df_parcours1.reset_index() df_parcours2 = df_parcours2.reset_index() df_parcours = df_parcours1.merge(df_parcours2, on=['Nom complet', 'ID du contact'], how='left') conditions = [ (df_info_parcours['âge'] < 25), (df_info_parcours['âge'] < 40), (df_info_parcours['âge'] < 60) ] choices = ['0-25 ans', '25-40 ans', '40-60 ans'] df_info_parcours['catégories âge'] = np.select(conditions, choices, default='60 ans et plus') df_info_parcours['RFM-Date Première Souscription'] = pd.to_datetime(df_info_parcours['RFM-Date Première Souscription'], dayfirst=True) conditions = [ (df_info_parcours['RFM-Date Première Souscription'] <= pd.to_datetime('2012')), (df_info_parcours['RFM-Date Première Souscription'] <= pd.to_datetime('2017')) ] choices = ['Nouvel actionnaire en 2012 ou moins', 'Nouvel actionnaire entre 2012 à 2017'] df_info_parcours['ancienneté actionnaires'] = np.select(conditions, choices, default='Nouvel actionnaire depuis 2017 ou plus') df_info_parcours['RFM-Date Première Souscription'] = pd.to_datetime(df_info_parcours['RFM-Date Première Souscription'], format='%d/%m/%Y') df_info_parcours['répartition année nouveau actionnaire'] = df_info_parcours['RFM-Date Première Souscription'].dt.year twenty4_months_ago = datetime.now() - timedelta(days=730) df_info_parcours['RFM-Date Dernier Don'] = pd.to_datetime(df_info_parcours['RFM-Date Dernier Don'], format='%d/%m/%Y') df_info_parcours.loc[:, "multi-casquette ?"] = df_info_parcours.apply(lambda row: "Actionnaire-donateur" if row["Actionnaire ?"] == 1 and (row["Donateur N"] == 1 or row['RFM-Date Dernier Don'] >= twenty4_months_ago) and row["adhérent N"] == 0 and row['adhérent N-1'] == 0 else "Actionnaire-adhérent" if row["Actionnaire ?"] == 1 and (row["adhérent N"] == 1 or row['adhérent N-1'] == 1) and row["Donateur N"] == 0 and row['RFM-Date Dernier Don'] < twenty4_months_ago else "Triple-engagement" if row["Actionnaire ?"] == 1 and (row["adhérent N"] == 1 or row['adhérent N-1'] == 1) and (row["Donateur N"] == 1 or row['RFM-Date Dernier Don'] >= twenty4_months_ago) else "Plus actionnaire" if row["Actionnaire ?"] == 0 else "Actionaire uniquement", axis=1) colonnes_suppr = [ 'Type d\'enregistrement des contrats', 'Nombre d\'actions à l\'acquisition', 'A fait l\'objet d\'un reçu fiscal', 'Affectation', 'Mouvement de titre Name', 'Nature du mouvement', 'Date d\'activation', 'Date du Mouvement', 'Actions - Date de fin', 'Nombre d\'actions échangées' ] df_info_parcours = df_info_parcours.drop_duplicates(subset="ID du contact") df_info_parcours = df_info_parcours.drop(columns=colonnes_suppr) df_MS_infos = df_MS_infos[(df_MS_infos["Nature du mouvement"] == "Souscription") | (df_MS_infos["Nature du mouvement"] == "Rachat")] df_MS_infos = df_MS_infos.sort_values(by = ["ID du contact", "Nature du mouvement", "Date du Mouvement"]) df_MS_infos = df_MS_infos[["Nom complet","ID du contact","Nature du mouvement"]] df_MS_infos = df_MS_infos.groupby(["ID du contact", "Nature du mouvement"]).size().reset_index(name='Nombre de SS et de rachats') df_MS_infos = df_MS_infos.pivot_table(index=['ID du contact'], columns='Nature du mouvement', values='Nombre de SS et de rachats', aggfunc='sum') df_info_parcours = df_info_parcours.merge(df_MS_infos, on=[ 'ID du contact'], how='left') df_info_parcours = df_info_parcours.rename(columns={'Rachat': 'Nombre de rachats'}) df_info_parcours = df_info_parcours.rename(columns={'Souscription': 'Nombre de souscriptions'}) df_parcours = df_parcours.merge(df_info_parcours, on=["Nom complet",'ID du contact'], how='left') df_parcours['multi-souscripteur ?'] = df_parcours['Nombre de souscriptions'].apply(lambda x: x > 1) dfsousmoy = dfsousmoy[dfsousmoy["Nature du mouvement"] == "Souscription"] dfsousmoy['Nombre de souscriptions'] = dfsousmoy['ID du contact'].map(df['ID du contact'].value_counts()) dfsousmoy = dfsousmoy[["ID du contact", 'Nombre de souscriptions', "Nombre d'actions à l'acquisition"]] dfsousmoy = dfsousmoy.groupby('ID du contact').agg({'Nombre de souscriptions': 'first', 'Nombre d\'actions à l\'acquisition': 'sum'}).reset_index() dfsousmoy["Nombre moyen d'actions par souscription"] = dfsousmoy["Nombre d'actions à l'acquisition"]/dfsousmoy["Nombre de souscriptions"] dfsousmoy = dfsousmoy[["ID du contact", "Nombre moyen d'actions par souscription"]] df_parcours = df_parcours.merge(dfsousmoy, on=['ID du contact'], how='left') df_parcoursD = df_parcoursD[df_parcoursD["Actionnaire ?"] == True] df_parcoursD = df_parcoursD.drop_duplicates(subset = "ID du contact") df_parcoursD = df_parcoursD[["ID du contact","Foncière : Nombre d'actions détenues"]] # Calculer les déciles avec des intervalles égaux deciles = pd.qcut(df_parcoursD["Foncière : Nombre d'actions détenues"], q=11, duplicates='drop') # En utilisant duplicates='drop' la fonction supprimera les bornes en double. Cela signifie que si deux valeurs identiques tombent exactement sur une limite d'intervalle, l'une des bornes sera supprimée, de sorte que chaque limite d'intervalle est unique. Cela peut entraîner un nombre réduit d'intervalles si vos données ont beaucoup de valeurs identiques.Il faut donc prévoir des intervalles en plus pour en spécifier 10 soit utiliser q = 11 au lieu de 10 # Utilisez ces intervalles pour découper les déciles df_parcoursD['déciles actionnaire'] = deciles df_parcoursD['déciles actionnaire'] = df_parcoursD['déciles actionnaire'].cat.codes + 1 # Créer une nouvelle colonne avec la catégorie d1 à d10 df_parcoursD['Déciles actionnaires'] = 'Décile ' + df_parcoursD['déciles actionnaire'].astype(str) df_parcoursD = df_parcoursD[["ID du contact","Déciles actionnaires"]] df_parcours = df_parcours.merge(df_parcoursD, on=['ID du contact'], how='left') df_parcours['Déciles actionnaires'] = df_parcours['Déciles actionnaires'].fillna('plus actionnaire')
    In [7]:
    Copied!
    import warnings
    warnings.filterwarnings("ignore")
    
    
    df['Difference début fin'] = df['Nombre d\'actions à l\'acquisition'] - df['Nombre d\'actions échangées']
    
    df['retrait complet ou partiel'] = df['Difference début fin'].apply(lambda x: 'retrait complet' if x == 0 else 'retrait partiel')
    
    df['année rachat'] = df['Date du Mouvement'].dt.year
    
    
    df['Date d\'activation'] = pd.to_datetime(df['Date d\'activation'])
    
    
    df['Date d\'activation'] = df['Date d\'activation'].dt.floor('D')
    
    df['Date du Mouvement'] = pd.to_datetime(df['Date du Mouvement'], dayfirst=True)
    
    df['durée conservation'] = df['Date du Mouvement'] - df['Date d\'activation']
    df_don = df[df["Nature du mouvement"] == "Don TDL"]
    df_dongraph = df[df["Nature du mouvement"] == "Don TDL"]
    
    df_rachat = df[df["Nature du mouvement"] == "Rachat"]
    
    import warnings warnings.filterwarnings("ignore") df['Difference début fin'] = df['Nombre d\'actions à l\'acquisition'] - df['Nombre d\'actions échangées'] df['retrait complet ou partiel'] = df['Difference début fin'].apply(lambda x: 'retrait complet' if x == 0 else 'retrait partiel') df['année rachat'] = df['Date du Mouvement'].dt.year df['Date d\'activation'] = pd.to_datetime(df['Date d\'activation']) df['Date d\'activation'] = df['Date d\'activation'].dt.floor('D') df['Date du Mouvement'] = pd.to_datetime(df['Date du Mouvement'], dayfirst=True) df['durée conservation'] = df['Date du Mouvement'] - df['Date d\'activation'] df_don = df[df["Nature du mouvement"] == "Don TDL"] df_dongraph = df[df["Nature du mouvement"] == "Don TDL"] df_rachat = df[df["Nature du mouvement"] == "Rachat"]
    In [8]:
    Copied!
    import numpy as np
    
    # Convertir la colonne en type chaîne de caractères
    df['Date d\'activation'] = df['Date d\'activation'].astype(str)
    
    # Extraire l'année de la colonne "Date d'activation" et créer une nouvelle colonne
    df['répartition année'] = df['Date d\'activation'].str.extract(r'(\d{4})')
    
    
    
    
    
    conditions = [
        (df['âge'] < 25),
        (df['âge'] < 40),
        (df['âge'] < 60)
    ]
    
    choices = ['0-25 ans', '25-40 ans', '40-60 ans']
    
    df['catégories âge'] = np.select(conditions, choices, default='60 ans et plus')
    
    import numpy as np # Convertir la colonne en type chaîne de caractères df['Date d\'activation'] = df['Date d\'activation'].astype(str) # Extraire l'année de la colonne "Date d'activation" et créer une nouvelle colonne df['répartition année'] = df['Date d\'activation'].str.extract(r'(\d{4})') conditions = [ (df['âge'] < 25), (df['âge'] < 40), (df['âge'] < 60) ] choices = ['0-25 ans', '25-40 ans', '40-60 ans'] df['catégories âge'] = np.select(conditions, choices, default='60 ans et plus')
    In [9]:
    Copied!
    df['RFM-Date Première Souscription'] = pd.to_datetime(df['RFM-Date Première Souscription'], dayfirst=True)
    
    conditions = [
         (df['RFM-Date Première Souscription'] <= pd.to_datetime('2012')),
         (df['RFM-Date Première Souscription'] <= pd.to_datetime('2017'))
    ]
    
    choices = ['Nouvel actionnaire en 2012 ou moins', 'Nouvel actionnaire entre 2012 à 2017']
    
    df['ancienneté actionnaires'] = np.select(conditions, choices, default='Nouvel actionnaire depuis 2017 ou plus')
    df['RFM-Date Première Souscription'] = df['RFM-Date Première Souscription'].astype(str)
    df['répartition année nouveau actionnaire'] = df['RFM-Date Première Souscription'].str.extract(r'(\d{4})')
    
    df['RFM-Date Première Souscription'] = pd.to_datetime(df['RFM-Date Première Souscription'], dayfirst=True) conditions = [ (df['RFM-Date Première Souscription'] <= pd.to_datetime('2012')), (df['RFM-Date Première Souscription'] <= pd.to_datetime('2017')) ] choices = ['Nouvel actionnaire en 2012 ou moins', 'Nouvel actionnaire entre 2012 à 2017'] df['ancienneté actionnaires'] = np.select(conditions, choices, default='Nouvel actionnaire depuis 2017 ou plus') df['RFM-Date Première Souscription'] = df['RFM-Date Première Souscription'].astype(str) df['répartition année nouveau actionnaire'] = df['RFM-Date Première Souscription'].str.extract(r'(\d{4})')
    In [10]:
    Copied!
    dfpiechart = df[(df["Actionnaire ?"]==1) & (df["Nature du mouvement"] == "Souscription")]
    dfpiechart = dfpiechart.drop_duplicates(subset="ID du contact")
    
    dfpiechart = df[(df["Actionnaire ?"]==1) & (df["Nature du mouvement"] == "Souscription")] dfpiechart = dfpiechart.drop_duplicates(subset="ID du contact")
    In [11]:
    Copied!
    dfpiechart1 = df[df["Nature du mouvement"] == "Souscription"]
    dfpiechart1 = dfpiechart1.drop_duplicates(subset="ID du contact")
    
    dfpiechart1 = df[df["Nature du mouvement"] == "Souscription"] dfpiechart1 = dfpiechart1.drop_duplicates(subset="ID du contact")
    In [12]:
    Copied!
    import matplotlib.pyplot as plt
    
    # Calculer les valeurs et les étiquettes pour le pie chart
    counts = dfpiechart['ancienneté actionnaires'].value_counts()
    percentages = counts / counts.sum() * 100
    
    # Créer le pie chart
    plt.pie(counts, labels=counts.index, autopct='%1.1f%%', startangle=90)
    plt.title("Répartition des actionnaires par ancienneté")
    
    
    
    # Afficher le graphique
    plt.show()
    
    import matplotlib.pyplot as plt # Calculer les valeurs et les étiquettes pour le pie chart counts = dfpiechart['ancienneté actionnaires'].value_counts() percentages = counts / counts.sum() * 100 # Créer le pie chart plt.pie(counts, labels=counts.index, autopct='%1.1f%%', startangle=90) plt.title("Répartition des actionnaires par ancienneté") # Afficher le graphique plt.show()
    No description has been provided for this image
    In [13]:
    Copied!
    import matplotlib.pyplot as plt
     
    
    # Calculer les valeurs et les étiquettes pour le pie chart
    counts = dfpiechart['catégories âge'].value_counts()
    percentages = counts / counts.sum() * 100
    
    # Créer le pie chart
    plt.pie(counts, labels=counts.index, autopct='%1.1f%%', startangle=90)
    plt.title("Actionnaires par catégories d'âge")
    
    
    
    # Afficher le graphique
    plt.show()
    
    import matplotlib.pyplot as plt # Calculer les valeurs et les étiquettes pour le pie chart counts = dfpiechart['catégories âge'].value_counts() percentages = counts / counts.sum() * 100 # Créer le pie chart plt.pie(counts, labels=counts.index, autopct='%1.1f%%', startangle=90) plt.title("Actionnaires par catégories d'âge") # Afficher le graphique plt.show()
    No description has been provided for this image
    In [14]:
    Copied!
    dfpiechart.rename(columns={'Territoire Terre de Liens': 'Territoire d\'habitation renseigné'}, inplace=True)
    
    dfpiechart.rename(columns={'Territoire Terre de Liens': 'Territoire d\'habitation renseigné'}, inplace=True)
    In [15]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    
    # Insérer un saut de page
    display(HTML("<div style='page-break-before: always;'></div>"))
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h2>Création distinction multi casquette et multi souscripteur, répartition des actionnaires par nombre de souscriptions, catégories de souscriptions par nombre d'actions</h2>"))
    
    from IPython.display import display, Markdown, HTML # Insérer un saut de page display(HTML("
    ")) # Afficher un titre avec une taille de police plus grande display(HTML("

    Création distinction multi casquette et multi souscripteur, répartition des actionnaires par nombre de souscriptions, catégories de souscriptions par nombre d'actions

    "))

    Création distinction multi casquette et multi souscripteur, répartition des actionnaires par nombre de souscriptions, catégories de souscriptions par nombre d'actions

    In [16]:
    Copied!
    from datetime import datetime, timedelta
    
    df['RFM-Date Dernier Don'] = pd.to_datetime(df['RFM-Date Dernier Don'], format='%d/%m/%Y')
    
    df2 = df[df["Nature du mouvement"]=="Souscription"]
    df3 = df2[df2["Actionnaire ?"]==1]
    twenty4_months_ago = datetime.now() - timedelta(days=730)
    df3.loc[:, "multi-casquette ?"] = df3.apply(lambda row: "Actionnaire-donateur" if row["Actionnaire ?"] == 1 and (row["Donateur N"] == 1 or row['RFM-Date Dernier Don'] >= twenty4_months_ago)  and row["adhérent N"] == 0 and row['adhérent N-1'] == 0
                                                else "Actionnaire-adhérent" if row["Actionnaire ?"] == 1 and (row["adhérent N"] == 1 or row['adhérent N-1'] == 1) and row["Donateur N"] == 0 and row['RFM-Date Dernier Don'] < twenty4_months_ago
                                                else "Triple-engagement" if row["Actionnaire ?"] == 1 and (row["adhérent N"] == 1 or row['adhérent N-1'] == 1) and (row["Donateur N"] == 1 or row['RFM-Date Dernier Don'] >= twenty4_months_ago)
                                                else "Actionnaire uniquement", axis=1)
    
    df3.loc[:, 'multi-souscripteur ?'] = df3.duplicated(subset='ID du contact', keep=False)
    
    df3.loc[:, 'Nombre de souscriptions'] = 1
    
    df_MS = df3.groupby('ID du contact').agg({"Nombre d'actions à l'acquisition": 'sum', 'Nombre de souscriptions': 'sum'})
    
    df_MS
    
    conditions = [
         (df_MS['Nombre de souscriptions'] < 2),
         (df_MS['Nombre de souscriptions'] <3),
         (df_MS['Nombre de souscriptions'] <=5),
         (df_MS['Nombre de souscriptions'] <=10),
    ]
    
    choices = ['1 souscription', "2 souscriptions" , "3 à 5 souscriptions","6 à 10 souscriptions"]
    
    df_MS['Catégories souscripteurs'] = np.select(conditions, choices, default='10 souscriptions et plus')
    
    df_MS = df_MS.merge(df3[['ID du contact','multi-casquette ?','multi-souscripteur ?','ancienneté actionnaires','catégories âge', "Territoire Terre de Liens"]], on='ID du contact', how='left')
    df_MS = df_MS.drop_duplicates(subset = "ID du contact")
    import pandas as pd
    
    # Calculer les valeurs et les étiquettes pour le pie chart
    counts = df_MS['Catégories souscripteurs'].value_counts()
    percentages = counts / counts.sum() * 100
    
    # Créer le DataFrame à partir des valeurs calculées
    df_cat_nbactions = pd.DataFrame({'Catégories souscripteurs': counts.index,
                             'Nombre de souscripteurs': counts.values,
                             'Pourcentage': percentages.values})
    
    
    df_cat_nbactions
    
    # Créer le pie chart
    plt.pie(counts, labels=counts.index, autopct='%1.1f%%', startangle=20)
    plt.title("Répartitions des actionnaires par nombre de souscriptions")
    
    
    
    # Afficher le graphique
    plt.show()
    
    from datetime import datetime, timedelta df['RFM-Date Dernier Don'] = pd.to_datetime(df['RFM-Date Dernier Don'], format='%d/%m/%Y') df2 = df[df["Nature du mouvement"]=="Souscription"] df3 = df2[df2["Actionnaire ?"]==1] twenty4_months_ago = datetime.now() - timedelta(days=730) df3.loc[:, "multi-casquette ?"] = df3.apply(lambda row: "Actionnaire-donateur" if row["Actionnaire ?"] == 1 and (row["Donateur N"] == 1 or row['RFM-Date Dernier Don'] >= twenty4_months_ago) and row["adhérent N"] == 0 and row['adhérent N-1'] == 0 else "Actionnaire-adhérent" if row["Actionnaire ?"] == 1 and (row["adhérent N"] == 1 or row['adhérent N-1'] == 1) and row["Donateur N"] == 0 and row['RFM-Date Dernier Don'] < twenty4_months_ago else "Triple-engagement" if row["Actionnaire ?"] == 1 and (row["adhérent N"] == 1 or row['adhérent N-1'] == 1) and (row["Donateur N"] == 1 or row['RFM-Date Dernier Don'] >= twenty4_months_ago) else "Actionnaire uniquement", axis=1) df3.loc[:, 'multi-souscripteur ?'] = df3.duplicated(subset='ID du contact', keep=False) df3.loc[:, 'Nombre de souscriptions'] = 1 df_MS = df3.groupby('ID du contact').agg({"Nombre d'actions à l'acquisition": 'sum', 'Nombre de souscriptions': 'sum'}) df_MS conditions = [ (df_MS['Nombre de souscriptions'] < 2), (df_MS['Nombre de souscriptions'] <3), (df_MS['Nombre de souscriptions'] <=5), (df_MS['Nombre de souscriptions'] <=10), ] choices = ['1 souscription', "2 souscriptions" , "3 à 5 souscriptions","6 à 10 souscriptions"] df_MS['Catégories souscripteurs'] = np.select(conditions, choices, default='10 souscriptions et plus') df_MS = df_MS.merge(df3[['ID du contact','multi-casquette ?','multi-souscripteur ?','ancienneté actionnaires','catégories âge', "Territoire Terre de Liens"]], on='ID du contact', how='left') df_MS = df_MS.drop_duplicates(subset = "ID du contact") import pandas as pd # Calculer les valeurs et les étiquettes pour le pie chart counts = df_MS['Catégories souscripteurs'].value_counts() percentages = counts / counts.sum() * 100 # Créer le DataFrame à partir des valeurs calculées df_cat_nbactions = pd.DataFrame({'Catégories souscripteurs': counts.index, 'Nombre de souscripteurs': counts.values, 'Pourcentage': percentages.values}) df_cat_nbactions # Créer le pie chart plt.pie(counts, labels=counts.index, autopct='%1.1f%%', startangle=20) plt.title("Répartitions des actionnaires par nombre de souscriptions") # Afficher le graphique plt.show()
    No description has been provided for this image
    In [17]:
    Copied!
    df2 = df.copy()
    df2= df2[df2["Nature du mouvement"]== "Souscription"]
    
    df2["catégorie souscription"] = df2.apply( lambda row : "Souscription de 5 actions ou moins" if row["Nombre d'actions à l'acquisition"] <=5
                                              else "Souscription de 6 à 50 actions" if row["Nombre d'actions à l'acquisition"] <= 50
                                              else "Souscriptions de 51 à 100 actions" if row["Nombre d'actions à l'acquisition"] <= 100
                                              else "Souscriptions de plus de 100 actions",
                                              axis = 1) 
    
    counts = df2['catégorie souscription'].value_counts()
    percentages = counts / counts.sum() * 100
    
    plt.pie(counts, labels=counts.index, autopct='%1.1f%%', startangle=20)
    plt.title("Répartitions des  souscriptions par nombre d'actions")
    
    
    
    # Afficher le graphique
    plt.show()
    
    df2 = df.copy() df2= df2[df2["Nature du mouvement"]== "Souscription"] df2["catégorie souscription"] = df2.apply( lambda row : "Souscription de 5 actions ou moins" if row["Nombre d'actions à l'acquisition"] <=5 else "Souscription de 6 à 50 actions" if row["Nombre d'actions à l'acquisition"] <= 50 else "Souscriptions de 51 à 100 actions" if row["Nombre d'actions à l'acquisition"] <= 100 else "Souscriptions de plus de 100 actions", axis = 1) counts = df2['catégorie souscription'].value_counts() percentages = counts / counts.sum() * 100 plt.pie(counts, labels=counts.index, autopct='%1.1f%%', startangle=20) plt.title("Répartitions des souscriptions par nombre d'actions") # Afficher le graphique plt.show()
    No description has been provided for this image
    In [18]:
    Copied!
    import matplotlib.pyplot as plt
    
    # Calculer les valeurs et les étiquettes pour le pie chart
    counts = df_MS['multi-casquette ?'].value_counts()
    percentages = counts / counts.sum() * 100
    
    # Créer le pie chart
    plt.pie(counts, labels=counts.index, autopct='%1.1f%%', startangle=180)
    plt.title("Répartition des actionnaires en fonction de leurs autres rôles")
    
    
    
    # Afficher le graphique
    plt.show()
    
    import matplotlib.pyplot as plt # Calculer les valeurs et les étiquettes pour le pie chart counts = df_MS['multi-casquette ?'].value_counts() percentages = counts / counts.sum() * 100 # Créer le pie chart plt.pie(counts, labels=counts.index, autopct='%1.1f%%', startangle=180) plt.title("Répartition des actionnaires en fonction de leurs autres rôles") # Afficher le graphique plt.show()
    No description has been provided for this image
    In [19]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Il s'agit de savoir si les actionnaires actuels sont également donateurs N ou adhérent N ou les 3 à la fois (triples-casquettes)</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Il s'agit de savoir si les actionnaires actuels sont également donateurs N ou adhérent N ou les 3 à la fois (triples-casquettes)

    "))

    Il s'agit de savoir si les actionnaires actuels sont également donateurs N ou adhérent N ou les 3 à la fois (triples-casquettes)

    In [20]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>On se rend compte que si l'actionnaire est multi-engagé, il privilégie les 3 types d'engagement combinés</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    On se rend compte que si l'actionnaire est multi-engagé, il privilégie les 3 types d'engagement combinés

    "))

    On se rend compte que si l'actionnaire est multi-engagé, il privilégie les 3 types d'engagement combinés

    In [21]:
    Copied!
    df_MS['multi-souscripteur ?'] = df_MS ['multi-souscripteur ?'].replace({True: "multi-souscripteurs", False: "souscripteurs uniques"})
    
    df_MS['multi-souscripteur ?'] = df_MS ['multi-souscripteur ?'].replace({True: "multi-souscripteurs", False: "souscripteurs uniques"})
    In [22]:
    Copied!
    import matplotlib.pyplot as plt
    
    # Calculer les valeurs et les étiquettes pour le pie chart
    counts = df_MS ['multi-souscripteur ?'].value_counts()
    percentages = counts / counts.sum() * 100
    
    # Créer le pie chart
    plt.pie(counts, labels=counts.index, autopct='%1.1f%%', startangle=90)
    plt.title("Répartition des types d'actionnaires en fonction du nombre de souscriptions détenues")
    
    
    
    # Afficher le graphique
    plt.show()
    
    import matplotlib.pyplot as plt # Calculer les valeurs et les étiquettes pour le pie chart counts = df_MS ['multi-souscripteur ?'].value_counts() percentages = counts / counts.sum() * 100 # Créer le pie chart plt.pie(counts, labels=counts.index, autopct='%1.1f%%', startangle=90) plt.title("Répartition des types d'actionnaires en fonction du nombre de souscriptions détenues") # Afficher le graphique plt.show()
    No description has been provided for this image
    In [23]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Sont souscripteurs uniques les actionnaires qui n'ont qu'une seule souscription et sont multi-souscripteurs les actionnaires qui ont plus d'une souscription</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Sont souscripteurs uniques les actionnaires qui n'ont qu'une seule souscription et sont multi-souscripteurs les actionnaires qui ont plus d'une souscription

    "))

    Sont souscripteurs uniques les actionnaires qui n'ont qu'une seule souscription et sont multi-souscripteurs les actionnaires qui ont plus d'une souscription

    In [24]:
    Copied!
    from IPython.display import display, HTML
    
    # Insérer un saut de page
    display(HTML("<div style='page-break-before: always;'></div>"))
    
    # Afficher un titre avec une taille de police plus grande et souligné
    display(HTML("<h2><u>Croisement données âges, territoire terre de liens, ancienneté des actionnaires, catégories des multisouscripteurs, multi-souscription et multi-casquette</u></h2>"))
    
    from IPython.display import display, HTML # Insérer un saut de page display(HTML("
    ")) # Afficher un titre avec une taille de police plus grande et souligné display(HTML("

    Croisement données âges, territoire terre de liens, ancienneté des actionnaires, catégories des multisouscripteurs, multi-souscription et multi-casquette

    "))

    Croisement données âges, territoire terre de liens, ancienneté des actionnaires, catégories des multisouscripteurs, multi-souscription et multi-casquette

    In [25]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h2>Croisement données âges, territoire terre de liens, ancienneté des actionnaires, catégories des multis-souscripteurs, multi-souscription et multi-casquette</h2>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Croisement données âges, territoire terre de liens, ancienneté des actionnaires, catégories des multis-souscripteurs, multi-souscription et multi-casquette

    "))

    Croisement données âges, territoire terre de liens, ancienneté des actionnaires, catégories des multis-souscripteurs, multi-souscription et multi-casquette

    In [26]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Répartition des actionnaires en fonction du nombre de souscriptions et de leur âge</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Répartition des actionnaires en fonction du nombre de souscriptions et de leur âge

    "))

    Répartition des actionnaires en fonction du nombre de souscriptions et de leur âge

    In [27]:
    Copied!
    df_MS_age = pd.crosstab(index=df_MS['catégories âge'], columns=df_MS['Catégories souscripteurs'], margins=True, margins_name='Total')
    new_column_order = ["1 souscription","2 souscriptions", "3 à 5 souscriptions", "6 à 10 souscriptions", "10 souscriptions et plus","Total"]
    df_MS_age = df_MS_age.reindex(columns=new_column_order)
    df_MS_age
    
    df_MS_age = pd.crosstab(index=df_MS['catégories âge'], columns=df_MS['Catégories souscripteurs'], margins=True, margins_name='Total') new_column_order = ["1 souscription","2 souscriptions", "3 à 5 souscriptions", "6 à 10 souscriptions", "10 souscriptions et plus","Total"] df_MS_age = df_MS_age.reindex(columns=new_column_order) df_MS_age
    Out[27]:
    Catégories souscripteurs 1 souscription 2 souscriptions 3 à 5 souscriptions 6 à 10 souscriptions 10 souscriptions et plus Total
    catégories âge
    0-25 ans 1458 683 308 25 0 2474
    25-40 ans 789 382 191 9 2 1373
    40-60 ans 1129 539 242 17 5 1932
    60 ans et plus 1780 870 329 21 7 3007
    Total 5156 2474 1070 72 14 8786
    In [28]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>% de répartition entre les catégories d'âges pour chaque catégorie de souscription</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    % de répartition entre les catégories d'âges pour chaque catégorie de souscription

    "))

    % de répartition entre les catégories d'âges pour chaque catégorie de souscription

    In [29]:
    Copied!
    df_col_percent = df_MS_age.copy()
    df_col_percent = df_col_percent.div(df_col_percent.loc['Total']) * 100
    df_col_percent = df_col_percent.round(1)
    df_col_percent.iloc[-1] = df_col_percent.iloc[:-1].sum()  # Ajouter la somme des pourcentages dans la dernière ligne
    df_col_percent
    
    df_col_percent = df_MS_age.copy() df_col_percent = df_col_percent.div(df_col_percent.loc['Total']) * 100 df_col_percent = df_col_percent.round(1) df_col_percent.iloc[-1] = df_col_percent.iloc[:-1].sum() # Ajouter la somme des pourcentages dans la dernière ligne df_col_percent
    Out[29]:
    Catégories souscripteurs 1 souscription 2 souscriptions 3 à 5 souscriptions 6 à 10 souscriptions 10 souscriptions et plus Total
    catégories âge
    0-25 ans 28.3 27.6 28.8 34.7 0.0 28.2
    25-40 ans 15.3 15.4 17.9 12.5 14.3 15.6
    40-60 ans 21.9 21.8 22.6 23.6 35.7 22.0
    60 ans et plus 34.5 35.2 30.7 29.2 50.0 34.2
    Total 100.0 100.0 100.0 100.0 100.0 100.0
    In [30]:
    Copied!
    df_row_percent = df_MS_age.copy()
    df_row_percent.iloc[:, :-1] = df_row_percent.iloc[:, :-1].div(df_row_percent['Total'], axis=0) * 100
    df_row_percent = df_row_percent.round(1)
    df_row_percent['Total'] = df_row_percent.iloc[:, :-1].sum(axis=1)  
    
    df_row_percent
    
    df_row_percent = df_MS_age.copy() df_row_percent.iloc[:, :-1] = df_row_percent.iloc[:, :-1].div(df_row_percent['Total'], axis=0) * 100 df_row_percent = df_row_percent.round(1) df_row_percent['Total'] = df_row_percent.iloc[:, :-1].sum(axis=1) df_row_percent
    Out[30]:
    Catégories souscripteurs 1 souscription 2 souscriptions 3 à 5 souscriptions 6 à 10 souscriptions 10 souscriptions et plus Total
    catégories âge
    0-25 ans 58.9 27.6 12.4 1.0 0.0 99.9
    25-40 ans 57.5 27.8 13.9 0.7 0.1 100.0
    40-60 ans 58.4 27.9 12.5 0.9 0.3 100.0
    60 ans et plus 59.2 28.9 10.9 0.7 0.2 99.9
    Total 58.7 28.2 12.2 0.8 0.2 100.1
    In [31]:
    Copied!
    df5 = df3.drop_duplicates(subset="ID du contact")
    
    df5 = df3.drop_duplicates(subset="ID du contact")
    In [32]:
    Copied!
    df_age_MS = pd.crosstab(index=df_MS['catégories âge'], columns=df_MS['multi-souscripteur ?'], margins=True, margins_name='Total')
    df_age_MS
    
    df_age_MS = pd.crosstab(index=df_MS['catégories âge'], columns=df_MS['multi-souscripteur ?'], margins=True, margins_name='Total') df_age_MS
    Out[32]:
    multi-souscripteur ? multi-souscripteurs souscripteurs uniques Total
    catégories âge
    0-25 ans 1016 1458 2474
    25-40 ans 584 789 1373
    40-60 ans 803 1129 1932
    60 ans et plus 1227 1780 3007
    Total 3630 5156 8786
    In [33]:
    Copied!
    df_col_percent = df_age_MS.copy()
    df_col_percent = df_col_percent.div(df_col_percent.loc['Total']) * 100
    df_col_percent = df_col_percent.round(1)
    df_col_percent.iloc[-1] = df_col_percent.iloc[:-1].sum()  # Ajouter la somme des pourcentages dans la dernière ligne
    df_col_percent
    
    df_col_percent = df_age_MS.copy() df_col_percent = df_col_percent.div(df_col_percent.loc['Total']) * 100 df_col_percent = df_col_percent.round(1) df_col_percent.iloc[-1] = df_col_percent.iloc[:-1].sum() # Ajouter la somme des pourcentages dans la dernière ligne df_col_percent
    Out[33]:
    multi-souscripteur ? multi-souscripteurs souscripteurs uniques Total
    catégories âge
    0-25 ans 28.0 28.3 28.2
    25-40 ans 16.1 15.3 15.6
    40-60 ans 22.1 21.9 22.0
    60 ans et plus 33.8 34.5 34.2
    Total 100.0 100.0 100.0
    In [34]:
    Copied!
    df_row_percent = df_age_MS.copy()
    df_row_percent.iloc[:, :-1] = df_row_percent.iloc[:, :-1].div(df_row_percent['Total'], axis=0) * 100
    df_row_percent = df_row_percent.round(1)
    df_row_percent['Total'] = df_row_percent.iloc[:, :-1].sum(axis=1)  
    
    df_row_percent
    
    df_row_percent = df_age_MS.copy() df_row_percent.iloc[:, :-1] = df_row_percent.iloc[:, :-1].div(df_row_percent['Total'], axis=0) * 100 df_row_percent = df_row_percent.round(1) df_row_percent['Total'] = df_row_percent.iloc[:, :-1].sum(axis=1) df_row_percent
    Out[34]:
    multi-souscripteur ? multi-souscripteurs souscripteurs uniques Total
    catégories âge
    0-25 ans 41.1 58.9 100.0
    25-40 ans 42.5 57.5 100.0
    40-60 ans 41.6 58.4 100.0
    60 ans et plus 40.8 59.2 100.0
    Total 41.3 58.7 100.0
    In [35]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Catégories des multi-souscripteurs et multi-engagnement ?</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Catégories des multi-souscripteurs et multi-engagnement ?

    "))

    Catégories des multi-souscripteurs et multi-engagnement ?

    In [36]:
    Copied!
    ordre_categories = ['1 souscription', '2 souscriptions', '3 à 5 souscriptions', '6 à 10 souscriptions', '10 souscriptions et plus']
    df_MS_MC = pd.crosstab(index=df_MS['multi-casquette ?'], columns=df_MS['Catégories souscripteurs'], margins=True, margins_name='Total')
    df_MS_MC = df_MS_MC[ordre_categories + ['Total']]  
    df_MS_MC
    
    ordre_categories = ['1 souscription', '2 souscriptions', '3 à 5 souscriptions', '6 à 10 souscriptions', '10 souscriptions et plus'] df_MS_MC = pd.crosstab(index=df_MS['multi-casquette ?'], columns=df_MS['Catégories souscripteurs'], margins=True, margins_name='Total') df_MS_MC = df_MS_MC[ordre_categories + ['Total']] df_MS_MC
    Out[36]:
    Catégories souscripteurs 1 souscription 2 souscriptions 3 à 5 souscriptions 6 à 10 souscriptions 10 souscriptions et plus Total
    multi-casquette ?
    Actionnaire uniquement 632 265 122 4 1 1024
    Actionnaire-adhérent 1805 924 385 30 4 3148
    Actionnaire-donateur 681 344 130 11 5 1171
    Triple-engagement 2038 941 433 27 4 3443
    Total 5156 2474 1070 72 14 8786
    In [37]:
    Copied!
    df_col_percent = df_MS_MC.copy()
    df_col_percent = df_col_percent.div(df_col_percent.loc['Total']) * 100
    df_col_percent = df_col_percent.round(1)
    df_col_percent.iloc[-1] = df_col_percent.iloc[:-1].sum()  # Ajouter la somme des pourcentages dans la dernière ligne
    df_col_percent
    
    df_col_percent = df_MS_MC.copy() df_col_percent = df_col_percent.div(df_col_percent.loc['Total']) * 100 df_col_percent = df_col_percent.round(1) df_col_percent.iloc[-1] = df_col_percent.iloc[:-1].sum() # Ajouter la somme des pourcentages dans la dernière ligne df_col_percent
    Out[37]:
    Catégories souscripteurs 1 souscription 2 souscriptions 3 à 5 souscriptions 6 à 10 souscriptions 10 souscriptions et plus Total
    multi-casquette ?
    Actionnaire uniquement 12.3 10.7 11.4 5.6 7.1 11.7
    Actionnaire-adhérent 35.0 37.3 36.0 41.7 28.6 35.8
    Actionnaire-donateur 13.2 13.9 12.1 15.3 35.7 13.3
    Triple-engagement 39.5 38.0 40.5 37.5 28.6 39.2
    Total 100.0 99.9 100.0 100.1 100.0 100.0
    In [38]:
    Copied!
    df_row_percent = df_MS_MC.copy()
    df_row_percent.iloc[:, :-1] = df_row_percent.iloc[:, :-1].div(df_row_percent['Total'], axis=0) * 100
    df_row_percent = df_row_percent.round(1)
    df_row_percent['Total'] = df_row_percent.iloc[:, :-1].sum(axis=1)  
    
    df_row_percent
    
    df_row_percent = df_MS_MC.copy() df_row_percent.iloc[:, :-1] = df_row_percent.iloc[:, :-1].div(df_row_percent['Total'], axis=0) * 100 df_row_percent = df_row_percent.round(1) df_row_percent['Total'] = df_row_percent.iloc[:, :-1].sum(axis=1) df_row_percent
    Out[38]:
    Catégories souscripteurs 1 souscription 2 souscriptions 3 à 5 souscriptions 6 à 10 souscriptions 10 souscriptions et plus Total
    multi-casquette ?
    Actionnaire uniquement 61.7 25.9 11.9 0.4 0.1 100.0
    Actionnaire-adhérent 57.3 29.4 12.2 1.0 0.1 100.0
    Actionnaire-donateur 58.2 29.4 11.1 0.9 0.4 100.0
    Triple-engagement 59.2 27.3 12.6 0.8 0.1 100.0
    Total 58.7 28.2 12.2 0.8 0.2 100.1
    In [39]:
    Copied!
    df_nbcroisés = pd.crosstab(index=df_MS['multi-casquette ?'], columns=df_MS['multi-souscripteur ?'], margins=True, margins_name='Total')
    df_nbcroisés
    
    df_nbcroisés = pd.crosstab(index=df_MS['multi-casquette ?'], columns=df_MS['multi-souscripteur ?'], margins=True, margins_name='Total') df_nbcroisés
    Out[39]:
    multi-souscripteur ? multi-souscripteurs souscripteurs uniques Total
    multi-casquette ?
    Actionnaire uniquement 392 632 1024
    Actionnaire-adhérent 1343 1805 3148
    Actionnaire-donateur 490 681 1171
    Triple-engagement 1405 2038 3443
    Total 3630 5156 8786
    In [40]:
    Copied!
    df_col_percent = df_nbcroisés.copy()
    df_col_percent = df_col_percent.div(df_col_percent.loc['Total']) * 100
    df_col_percent = df_col_percent.round(1)
    df_col_percent.iloc[-1] = df_col_percent.iloc[:-1].sum()  # Ajouter la somme des pourcentages dans la dernière ligne
    df_col_percent
    
    df_col_percent = df_nbcroisés.copy() df_col_percent = df_col_percent.div(df_col_percent.loc['Total']) * 100 df_col_percent = df_col_percent.round(1) df_col_percent.iloc[-1] = df_col_percent.iloc[:-1].sum() # Ajouter la somme des pourcentages dans la dernière ligne df_col_percent
    Out[40]:
    multi-souscripteur ? multi-souscripteurs souscripteurs uniques Total
    multi-casquette ?
    Actionnaire uniquement 10.8 12.3 11.7
    Actionnaire-adhérent 37.0 35.0 35.8
    Actionnaire-donateur 13.5 13.2 13.3
    Triple-engagement 38.7 39.5 39.2
    Total 100.0 100.0 100.0
    In [41]:
    Copied!
    df_row_percent = df_nbcroisés.copy()
    df_row_percent.iloc[:, :-1] = df_row_percent.iloc[:, :-1].div(df_row_percent['Total'], axis=0) * 100
    df_row_percent = df_row_percent.round(1)
    df_row_percent['Total'] = df_row_percent.iloc[:, :-1].sum(axis=1)  
    
    df_row_percent
    
    df_row_percent = df_nbcroisés.copy() df_row_percent.iloc[:, :-1] = df_row_percent.iloc[:, :-1].div(df_row_percent['Total'], axis=0) * 100 df_row_percent = df_row_percent.round(1) df_row_percent['Total'] = df_row_percent.iloc[:, :-1].sum(axis=1) df_row_percent
    Out[41]:
    multi-souscripteur ? multi-souscripteurs souscripteurs uniques Total
    multi-casquette ?
    Actionnaire uniquement 38.3 61.7 100.0
    Actionnaire-adhérent 42.7 57.3 100.0
    Actionnaire-donateur 41.8 58.2 100.0
    Triple-engagement 40.8 59.2 100.0
    Total 41.3 58.7 100.0
    In [42]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Catégories des multi-souscripteurs et ancienneté </h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Catégories des multi-souscripteurs et ancienneté

    "))

    Catégories des multi-souscripteurs et ancienneté

    In [43]:
    Copied!
    ordre_categories_souscripteurs = ['1 souscription', '2 souscriptions', '3 à 5 souscriptions', '6 à 10 souscriptions', '10 souscriptions et plus']
    ordre_categories_ancienneté = ['Nouvel actionnaire depuis 2017 ou plus', 'Nouvel actionnaire entre 2012 à 2017', 'Nouvel actionnaire en 2012 ou moins']
    df_MS_ancienneté = pd.crosstab(index=df_MS["Catégories souscripteurs"], columns=df_MS["ancienneté actionnaires"], margins=True, margins_name='Total')
    df_MS_ancienneté = df_MS_ancienneté.reindex(index=ordre_categories_souscripteurs, columns=ordre_categories_ancienneté)
    df_MS_ancienneté['Total'] = df_MS_ancienneté.sum(axis=1)
    df_MS_ancienneté.loc['Total'] = df_MS_ancienneté.sum()
    df_MS_ancienneté
    
    ordre_categories_souscripteurs = ['1 souscription', '2 souscriptions', '3 à 5 souscriptions', '6 à 10 souscriptions', '10 souscriptions et plus'] ordre_categories_ancienneté = ['Nouvel actionnaire depuis 2017 ou plus', 'Nouvel actionnaire entre 2012 à 2017', 'Nouvel actionnaire en 2012 ou moins'] df_MS_ancienneté = pd.crosstab(index=df_MS["Catégories souscripteurs"], columns=df_MS["ancienneté actionnaires"], margins=True, margins_name='Total') df_MS_ancienneté = df_MS_ancienneté.reindex(index=ordre_categories_souscripteurs, columns=ordre_categories_ancienneté) df_MS_ancienneté['Total'] = df_MS_ancienneté.sum(axis=1) df_MS_ancienneté.loc['Total'] = df_MS_ancienneté.sum() df_MS_ancienneté
    Out[43]:
    ancienneté actionnaires Nouvel actionnaire depuis 2017 ou plus Nouvel actionnaire entre 2012 à 2017 Nouvel actionnaire en 2012 ou moins Total
    Catégories souscripteurs
    1 souscription 1736 1541 1879 5156
    2 souscriptions 843 751 880 2474
    3 à 5 souscriptions 359 310 401 1070
    6 à 10 souscriptions 27 21 24 72
    10 souscriptions et plus 2 7 5 14
    Total 2967 2630 3189 8786
    In [44]:
    Copied!
    df_col_percent = df_MS_ancienneté.copy()
    df_col_percent = df_col_percent.div(df_col_percent.loc['Total']) * 100
    df_col_percent = df_col_percent.round(1)
    df_col_percent.iloc[-1] = df_col_percent.iloc[:-1].sum()  # Ajouter la somme des pourcentages dans la dernière ligne
    df_col_percent 
    
    df_col_percent = df_MS_ancienneté.copy() df_col_percent = df_col_percent.div(df_col_percent.loc['Total']) * 100 df_col_percent = df_col_percent.round(1) df_col_percent.iloc[-1] = df_col_percent.iloc[:-1].sum() # Ajouter la somme des pourcentages dans la dernière ligne df_col_percent
    Out[44]:
    ancienneté actionnaires Nouvel actionnaire depuis 2017 ou plus Nouvel actionnaire entre 2012 à 2017 Nouvel actionnaire en 2012 ou moins Total
    Catégories souscripteurs
    1 souscription 58.5 58.6 58.9 58.7
    2 souscriptions 28.4 28.6 27.6 28.2
    3 à 5 souscriptions 12.1 11.8 12.6 12.2
    6 à 10 souscriptions 0.9 0.8 0.8 0.8
    10 souscriptions et plus 0.1 0.3 0.2 0.2
    Total 100.0 100.1 100.1 100.1
    In [45]:
    Copied!
    df_row_percent = df_MS_ancienneté.copy()
    df_row_percent.iloc[:, :-1] = df_row_percent.iloc[:, :-1].div(df_row_percent['Total'], axis=0) * 100
    df_row_percent = df_row_percent.round(1)
    df_row_percent['Total'] = df_row_percent.iloc[:, :-1].sum(axis=1)  
    
    df_row_percent
    
    df_row_percent = df_MS_ancienneté.copy() df_row_percent.iloc[:, :-1] = df_row_percent.iloc[:, :-1].div(df_row_percent['Total'], axis=0) * 100 df_row_percent = df_row_percent.round(1) df_row_percent['Total'] = df_row_percent.iloc[:, :-1].sum(axis=1) df_row_percent
    Out[45]:
    ancienneté actionnaires Nouvel actionnaire depuis 2017 ou plus Nouvel actionnaire entre 2012 à 2017 Nouvel actionnaire en 2012 ou moins Total
    Catégories souscripteurs
    1 souscription 33.7 29.9 36.4 100.0
    2 souscriptions 34.1 30.4 35.6 100.1
    3 à 5 souscriptions 33.6 29.0 37.5 100.1
    6 à 10 souscriptions 37.5 29.2 33.3 100.0
    10 souscriptions et plus 14.3 50.0 35.7 100.0
    Total 33.8 29.9 36.3 100.0
    In [46]:
    Copied!
    df_ancienneté_MS = pd.crosstab(index=df_MS ['ancienneté actionnaires'], columns=df_MS ['multi-souscripteur ?'], margins=True, margins_name='Total')
    df_ancienneté_MS = df_ancienneté_MS.reindex(index=ordre_categories_ancienneté)
    df_ancienneté_MS.loc['Total'] = df_ancienneté_MS.sum()
    df_ancienneté_MS
    
    df_ancienneté_MS = pd.crosstab(index=df_MS ['ancienneté actionnaires'], columns=df_MS ['multi-souscripteur ?'], margins=True, margins_name='Total') df_ancienneté_MS = df_ancienneté_MS.reindex(index=ordre_categories_ancienneté) df_ancienneté_MS.loc['Total'] = df_ancienneté_MS.sum() df_ancienneté_MS
    Out[46]:
    multi-souscripteur ? multi-souscripteurs souscripteurs uniques Total
    ancienneté actionnaires
    Nouvel actionnaire depuis 2017 ou plus 1231 1736 2967
    Nouvel actionnaire entre 2012 à 2017 1089 1541 2630
    Nouvel actionnaire en 2012 ou moins 1310 1879 3189
    Total 3630 5156 8786
    In [ ]:
    Copied!
    
    
    In [47]:
    Copied!
    df_col_percent = df_ancienneté_MS.copy()
    df_col_percent = df_col_percent.div(df_col_percent.loc['Total']) * 100
    df_col_percent = df_col_percent.round(1)
    df_col_percent.iloc[-1] = df_col_percent.iloc[:-1].sum()  # Ajouter la somme des pourcentages dans la dernière ligne
    df_col_percent
    
    df_col_percent = df_ancienneté_MS.copy() df_col_percent = df_col_percent.div(df_col_percent.loc['Total']) * 100 df_col_percent = df_col_percent.round(1) df_col_percent.iloc[-1] = df_col_percent.iloc[:-1].sum() # Ajouter la somme des pourcentages dans la dernière ligne df_col_percent
    Out[47]:
    multi-souscripteur ? multi-souscripteurs souscripteurs uniques Total
    ancienneté actionnaires
    Nouvel actionnaire depuis 2017 ou plus 33.9 33.7 33.8
    Nouvel actionnaire entre 2012 à 2017 30.0 29.9 29.9
    Nouvel actionnaire en 2012 ou moins 36.1 36.4 36.3
    Total 100.0 100.0 100.0
    In [48]:
    Copied!
    df_row_percent = df_ancienneté_MS.copy()
    df_row_percent.iloc[:, :-1] = df_row_percent.iloc[:, :-1].div(df_row_percent['Total'], axis=0) * 100
    df_row_percent = df_row_percent.round(1)
    df_row_percent['Total'] = df_row_percent.iloc[:, :-1].sum(axis=1)  
    
    df_row_percent
    
    df_row_percent = df_ancienneté_MS.copy() df_row_percent.iloc[:, :-1] = df_row_percent.iloc[:, :-1].div(df_row_percent['Total'], axis=0) * 100 df_row_percent = df_row_percent.round(1) df_row_percent['Total'] = df_row_percent.iloc[:, :-1].sum(axis=1) df_row_percent
    Out[48]:
    multi-souscripteur ? multi-souscripteurs souscripteurs uniques Total
    ancienneté actionnaires
    Nouvel actionnaire depuis 2017 ou plus 41.5 58.5 100.0
    Nouvel actionnaire entre 2012 à 2017 41.4 58.6 100.0
    Nouvel actionnaire en 2012 ou moins 41.1 58.9 100.0
    Total 41.3 58.7 100.0
    In [49]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Ancienneté et multi-casquettes ? </h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Ancienneté et multi-casquettes ?

    "))

    Ancienneté et multi-casquettes ?

    In [50]:
    Copied!
    df_ancienneté_MC = pd.crosstab(index=df_MS['ancienneté actionnaires'], columns=df_MS['multi-casquette ?'], margins=True, margins_name='Total')
    df_ancienneté_MC = df_ancienneté_MC.reindex(index=ordre_categories_ancienneté)
    df_ancienneté_MC.loc['Total'] = df_ancienneté_MC.sum()
    
    df_ancienneté_MC = pd.crosstab(index=df_MS['ancienneté actionnaires'], columns=df_MS['multi-casquette ?'], margins=True, margins_name='Total') df_ancienneté_MC = df_ancienneté_MC.reindex(index=ordre_categories_ancienneté) df_ancienneté_MC.loc['Total'] = df_ancienneté_MC.sum()
    In [51]:
    Copied!
    # Calculer les pourcentages de colonnes
    df_col_percent_ancienneté_MC = df_ancienneté_MC.copy()
    df_col_percent_ancienneté_MC = df_col_percent_ancienneté_MC.div(df_col_percent_ancienneté_MC.loc['Total']) * 100
    df_col_percent_ancienneté_MC = df_col_percent_ancienneté_MC.round(1)
    df_col_percent_ancienneté_MC.iloc[-1] = df_col_percent_ancienneté_MC.iloc[:-1].sum()  # Ajouter la somme des pourcentages dans la dernière ligne
    df_col_percent_ancienneté_MC
    
    # Calculer les pourcentages de colonnes df_col_percent_ancienneté_MC = df_ancienneté_MC.copy() df_col_percent_ancienneté_MC = df_col_percent_ancienneté_MC.div(df_col_percent_ancienneté_MC.loc['Total']) * 100 df_col_percent_ancienneté_MC = df_col_percent_ancienneté_MC.round(1) df_col_percent_ancienneté_MC.iloc[-1] = df_col_percent_ancienneté_MC.iloc[:-1].sum() # Ajouter la somme des pourcentages dans la dernière ligne df_col_percent_ancienneté_MC
    Out[51]:
    multi-casquette ? Actionnaire uniquement Actionnaire-adhérent Actionnaire-donateur Triple-engagement Total
    ancienneté actionnaires
    Nouvel actionnaire depuis 2017 ou plus 31.5 34.1 33.3 34.3 33.8
    Nouvel actionnaire entre 2012 à 2017 30.8 29.5 29.7 30.1 29.9
    Nouvel actionnaire en 2012 ou moins 37.7 36.4 37.0 35.6 36.3
    Total 100.0 100.0 100.0 100.0 100.0
    In [52]:
    Copied!
    # Calculer les pourcentages de lignes
    df_row_percent_ancienneté_MC = df_ancienneté_MC.copy()
    df_row_percent_ancienneté_MC.iloc[:, :-1] = df_row_percent_ancienneté_MC.iloc[:, :-1].div(df_row_percent_ancienneté_MC['Total'], axis=0) * 100
    df_row_percent_ancienneté_MC = df_row_percent_ancienneté_MC.round(1)
    df_row_percent_ancienneté_MC['Total'] = df_row_percent_ancienneté_MC.iloc[:, :-1].sum(axis=1)
    df_row_percent_ancienneté_MC
    
    # Calculer les pourcentages de lignes df_row_percent_ancienneté_MC = df_ancienneté_MC.copy() df_row_percent_ancienneté_MC.iloc[:, :-1] = df_row_percent_ancienneté_MC.iloc[:, :-1].div(df_row_percent_ancienneté_MC['Total'], axis=0) * 100 df_row_percent_ancienneté_MC = df_row_percent_ancienneté_MC.round(1) df_row_percent_ancienneté_MC['Total'] = df_row_percent_ancienneté_MC.iloc[:, :-1].sum(axis=1) df_row_percent_ancienneté_MC
    Out[52]:
    multi-casquette ? Actionnaire uniquement Actionnaire-adhérent Actionnaire-donateur Triple-engagement Total
    ancienneté actionnaires
    Nouvel actionnaire depuis 2017 ou plus 10.9 36.2 13.1 39.8 100.0
    Nouvel actionnaire entre 2012 à 2017 12.0 35.3 13.2 39.5 100.0
    Nouvel actionnaire en 2012 ou moins 12.1 35.9 13.6 38.4 100.0
    Total 11.7 35.8 13.3 39.2 100.0
    In [53]:
    Copied!
    import pandas as pd
    
    # Grouper le DataFrame par la colonne "Nom complet" et agréger la somme des actions
    df_aggrégé = df3.groupby(['ID du contact', 'multi-casquette ?', 'multi-souscripteur ?',"catégories âge","ancienneté actionnaires"]).agg({'Nombre d\'actions à l\'acquisition': 'sum'}).reset_index()
    
    import pandas as pd # Grouper le DataFrame par la colonne "Nom complet" et agréger la somme des actions df_aggrégé = df3.groupby(['ID du contact', 'multi-casquette ?', 'multi-souscripteur ?',"catégories âge","ancienneté actionnaires"]).agg({'Nombre d\'actions à l\'acquisition': 'sum'}).reset_index()
    In [54]:
    Copied!
    df3['Nombre de souscriptions'] = df3['ID du contact'].map(df['ID du contact'].value_counts())
    
    df3['Nombre de souscriptions'] = df3['ID du contact'].map(df['ID du contact'].value_counts())
    In [55]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h2>Nombre d'actions total et moyen par multi-engagement et multi-souscripteurs</h2>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Nombre d'actions total et moyen par multi-engagement et multi-souscripteurs

    "))

    Nombre d'actions total et moyen par multi-engagement et multi-souscripteurs

    In [56]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Nombre moyen d'actions par multi-souscripteurs </h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Nombre moyen d'actions par multi-souscripteurs

    "))

    Nombre moyen d'actions par multi-souscripteurs

    In [57]:
    Copied!
    df_action_MSmean = df3.groupby("multi-souscripteur ?")["Nombre d'actions à l'acquisition"].mean().round().to_frame()
    df_action_MSmean
    
    df_action_MSmean = df3.groupby("multi-souscripteur ?")["Nombre d'actions à l'acquisition"].mean().round().to_frame() df_action_MSmean
    Out[57]:
    Nombre d'actions à l'acquisition
    multi-souscripteur ?
    False 55.0
    True 52.0
    In [58]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Nombre total d'actions par multi-souscripteurs </h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Nombre total d'actions par multi-souscripteurs

    "))

    Nombre total d'actions par multi-souscripteurs

    In [59]:
    Copied!
    df_action_MSsum = df3
    df_action_MSsum = df_action_MSsum.groupby("multi-souscripteur ?")["Nombre d'actions à l'acquisition"].sum().to_frame()
    df_action_MSsum
    
    df_action_MSsum = df3 df_action_MSsum = df_action_MSsum.groupby("multi-souscripteur ?")["Nombre d'actions à l'acquisition"].sum().to_frame() df_action_MSsum
    Out[59]:
    Nombre d'actions à l'acquisition
    multi-souscripteur ?
    False 281704
    True 478914
    In [60]:
    Copied!
    # Calculer la somme totale de la colonne "Foncière : Nombre d'actions détenues"
    total_sum = df_action_MSsum["Nombre d'actions à l'acquisition"].sum()
    
    
    print("Somme  des actions détenues", total_sum)
    
    # Calculer la somme totale de la colonne "Foncière : Nombre d'actions détenues" total_sum = df_action_MSsum["Nombre d'actions à l'acquisition"].sum() print("Somme des actions détenues", total_sum)
    Somme  des actions détenues 760618
    
    In [61]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Nombre moyen d'actions par multi-casquettes </h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Nombre moyen d'actions par multi-casquettes

    "))

    Nombre moyen d'actions par multi-casquettes

    In [62]:
    Copied!
    df_action_MCmean = df_aggrégé.groupby('multi-casquette ?')["Nombre d'actions à l'acquisition"].mean().round().to_frame()
    df_action_MCmean
    
    df_action_MCmean = df_aggrégé.groupby('multi-casquette ?')["Nombre d'actions à l'acquisition"].mean().round().to_frame() df_action_MCmean
    Out[62]:
    Nombre d'actions à l'acquisition
    multi-casquette ?
    Actionnaire uniquement 88.0
    Actionnaire-adhérent 87.0
    Actionnaire-donateur 92.0
    Triple-engagement 84.0
    In [63]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Nombre moyen d'actions par ancienneté </h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Nombre moyen d'actions par ancienneté

    "))

    Nombre moyen d'actions par ancienneté

    In [64]:
    Copied!
    df_action_ancienneté_mean = df_aggrégé.groupby('ancienneté actionnaires')["Nombre d'actions à l'acquisition"].mean().round().to_frame()
    df_action_ancienneté_mean = df_action_ancienneté_mean.reindex(index=ordre_categories_ancienneté)
    df_action_ancienneté_mean
    
    df_action_ancienneté_mean = df_aggrégé.groupby('ancienneté actionnaires')["Nombre d'actions à l'acquisition"].mean().round().to_frame() df_action_ancienneté_mean = df_action_ancienneté_mean.reindex(index=ordre_categories_ancienneté) df_action_ancienneté_mean
    Out[64]:
    Nombre d'actions à l'acquisition
    ancienneté actionnaires
    Nouvel actionnaire depuis 2017 ou plus 89.0
    Nouvel actionnaire entre 2012 à 2017 89.0
    Nouvel actionnaire en 2012 ou moins 83.0
    In [65]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Nombre moyen d'actions par nombre de souscriptions </h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Nombre moyen d'actions par nombre de souscriptions

    "))

    Nombre moyen d'actions par nombre de souscriptions

    In [66]:
    Copied!
    df2["catégorie souscription"] = df2.apply( lambda row : "Souscription de 5 actions ou moins" if row["Nombre d'actions à l'acquisition"] <=5
                                              else "Souscription de 6 à 50 actions" if row["Nombre d'actions à l'acquisition"] <= 50
                                              else "Souscriptions de 51 à 100 actions" if row["Nombre d'actions à l'acquisition"] <= 100
                                              else "Souscriptions de plus de 100 actions",
                                              axis = 1) 
    
    df2["catégorie souscription"] = df2.apply( lambda row : "Souscription de 5 actions ou moins" if row["Nombre d'actions à l'acquisition"] <=5 else "Souscription de 6 à 50 actions" if row["Nombre d'actions à l'acquisition"] <= 50 else "Souscriptions de 51 à 100 actions" if row["Nombre d'actions à l'acquisition"] <= 100 else "Souscriptions de plus de 100 actions", axis = 1)
    In [67]:
    Copied!
    df_cat_nbactions_mean = df_MS.groupby('Catégories souscripteurs')["Nombre d'actions à l'acquisition"].mean().round().to_frame()
    df_cat_nbactions_mean = df_cat_nbactions_mean.reindex(index=ordre_categories)
    df_cat_nbactions_mean
    
    df_cat_nbactions_mean = df_MS.groupby('Catégories souscripteurs')["Nombre d'actions à l'acquisition"].mean().round().to_frame() df_cat_nbactions_mean = df_cat_nbactions_mean.reindex(index=ordre_categories) df_cat_nbactions_mean
    Out[67]:
    Nombre d'actions à l'acquisition
    Catégories souscripteurs
    1 souscription 55.0
    2 souscriptions 105.0
    3 à 5 souscriptions 169.0
    6 à 10 souscriptions 420.0
    10 souscriptions et plus 486.0
    In [68]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Nombre total d'actions par nombre de souscriptions </h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Nombre total d'actions par nombre de souscriptions

    "))

    Nombre total d'actions par nombre de souscriptions

    In [69]:
    Copied!
    df_cat_nbactions_sum = df_MS.groupby('Catégories souscripteurs')["Nombre d'actions à l'acquisition"].sum().to_frame()
    df_cat_nbactions_sum = df_cat_nbactions_sum.reindex(index=ordre_categories)
    df_cat_nbactions_sum
    
    df_cat_nbactions_sum = df_MS.groupby('Catégories souscripteurs')["Nombre d'actions à l'acquisition"].sum().to_frame() df_cat_nbactions_sum = df_cat_nbactions_sum.reindex(index=ordre_categories) df_cat_nbactions_sum
    Out[69]:
    Nombre d'actions à l'acquisition
    Catégories souscripteurs
    1 souscription 281704
    2 souscriptions 260901
    3 à 5 souscriptions 180955
    6 à 10 souscriptions 30247
    10 souscriptions et plus 6811
    In [70]:
    Copied!
    # Calculer la somme totale de la colonne "Foncière : Nombre d'actions détenues"
    total_sum = df_cat_nbactions_sum["Nombre d'actions à l'acquisition"].sum()
    
    
    print("Somme  des actions prises (différent des actions détenues)", total_sum)
    
    # Calculer la somme totale de la colonne "Foncière : Nombre d'actions détenues" total_sum = df_cat_nbactions_sum["Nombre d'actions à l'acquisition"].sum() print("Somme des actions prises (différent des actions détenues)", total_sum)
    Somme  des actions prises (différent des actions détenues) 760618
    
    In [71]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Capital possédé par multi-souscripteurs</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Capital possédé par multi-souscripteurs

    "))

    Capital possédé par multi-souscripteurs

    In [72]:
    Copied!
    #df3.loc[:, "Foncière : Capital possédé"] = df3["Foncière : Capital possédé"].str.replace(',', '.').astype(float)
    #df3.loc[:, "Foncière : Part du capital possédée (%)"] = df3["Foncière : Part du capital possédée (%)"].str.replace(',', '.').astype(float)
    
    df4 = df3.drop_duplicates(subset="ID du contact")
    df_capital_MC = df4.groupby("multi-souscripteur ?").agg({
        "Foncière : Capital possédé": "sum",
        "Foncière : Part du capital possédée (%)": "sum"
    })
    df_capital_MC
    
    #df3.loc[:, "Foncière : Capital possédé"] = df3["Foncière : Capital possédé"].str.replace(',', '.').astype(float) #df3.loc[:, "Foncière : Part du capital possédée (%)"] = df3["Foncière : Part du capital possédée (%)"].str.replace(',', '.').astype(float) df4 = df3.drop_duplicates(subset="ID du contact") df_capital_MC = df4.groupby("multi-souscripteur ?").agg({ "Foncière : Capital possédé": "sum", "Foncière : Part du capital possédée (%)": "sum" }) df_capital_MC
    Out[72]:
    Foncière : Capital possédé Foncière : Part du capital possédée (%)
    multi-souscripteur ?
    False 412118805 51.881907
    True 282614850 35.578569
    In [73]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Capital possédé par catégories d'ancienneté</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Capital possédé par catégories d'ancienneté

    "))

    Capital possédé par catégories d'ancienneté

    In [74]:
    Copied!
    df6 = df3.drop_duplicates(subset="ID du contact")
    #df6.loc[:, "Foncière : Part du capital possédée (%)"] = df6["Foncière : Part du capital possédée (%)"].astype(float).apply(lambda x: round(float(x), 2))
    df_capital_ancienneté = df6.groupby("ancienneté actionnaires").agg({
        "Foncière : Capital possédé": "sum",
        "Foncière : Part du capital possédée (%)": "sum"
    })
    df_capital_ancienneté = df_capital_ancienneté.reindex(index=ordre_categories_ancienneté)
    df_capital_ancienneté
    
    df6 = df3.drop_duplicates(subset="ID du contact") #df6.loc[:, "Foncière : Part du capital possédée (%)"] = df6["Foncière : Part du capital possédée (%)"].astype(float).apply(lambda x: round(float(x), 2)) df_capital_ancienneté = df6.groupby("ancienneté actionnaires").agg({ "Foncière : Capital possédé": "sum", "Foncière : Part du capital possédée (%)": "sum" }) df_capital_ancienneté = df_capital_ancienneté.reindex(index=ordre_categories_ancienneté) df_capital_ancienneté
    Out[74]:
    Foncière : Capital possédé Foncière : Part du capital possédée (%)
    ancienneté actionnaires
    Nouvel actionnaire depuis 2017 ou plus 225978270 28.448553
    Nouvel actionnaire entre 2012 à 2017 206575845 26.005969
    Nouvel actionnaire en 2012 ou moins 262179540 33.005955
    In [75]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Capital possédé par nombre de souscriptions de l'actionnaire</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Capital possédé par nombre de souscriptions de l'actionnaire

    "))

    Capital possédé par nombre de souscriptions de l'actionnaire

    In [76]:
    Copied!
    conditions = [
         (df3['Nombre de souscriptions'] < 2),
         (df3['Nombre de souscriptions'] <3),
         (df3['Nombre de souscriptions'] <=5),
         (df3['Nombre de souscriptions'] <=10),
    ]
    
    choices = ['1 souscription', "2 souscriptions" , "3 à 5 souscriptions","6 à 10 souscriptions"]
    
    df3['Catégories souscripteurs'] = np.select(conditions, choices, default='10 souscriptions et plus')
    
    conditions = [ (df3['Nombre de souscriptions'] < 2), (df3['Nombre de souscriptions'] <3), (df3['Nombre de souscriptions'] <=5), (df3['Nombre de souscriptions'] <=10), ] choices = ['1 souscription', "2 souscriptions" , "3 à 5 souscriptions","6 à 10 souscriptions"] df3['Catégories souscripteurs'] = np.select(conditions, choices, default='10 souscriptions et plus')
    In [77]:
    Copied!
    df6 = df3.drop_duplicates(subset="ID du contact")
    #df6.loc[:, "Foncière : Part du capital possédée (%)"] = df6["Foncière : Part du capital possédée (%)"].astype(str).apply(lambda x: round(float(x), 2))
    df_capital_nbsous = df6.groupby("Catégories souscripteurs").agg({
        "Foncière : Capital possédé": "sum",
        "Foncière : Part du capital possédée (%)": "sum"
    })
    df_capital_nbsous =  df_capital_nbsous.reindex(index=ordre_categories)
    df_capital_nbsous
    
    df6 = df3.drop_duplicates(subset="ID du contact") #df6.loc[:, "Foncière : Part du capital possédée (%)"] = df6["Foncière : Part du capital possédée (%)"].astype(str).apply(lambda x: round(float(x), 2)) df_capital_nbsous = df6.groupby("Catégories souscripteurs").agg({ "Foncière : Capital possédé": "sum", "Foncière : Part du capital possédée (%)": "sum" }) df_capital_nbsous = df_capital_nbsous.reindex(index=ordre_categories) df_capital_nbsous
    Out[77]:
    Foncière : Capital possédé Foncière : Part du capital possédée (%)
    Catégories souscripteurs
    1 souscription 327246990 41.197339
    2 souscriptions 229901385 28.942437
    3 à 5 souscriptions 130627350 16.444763
    6 à 10 souscriptions 2308320 0.290596
    10 souscriptions et plus 4649610 0.585342
    In [78]:
    Copied!
    from IPython.display import display, HTML
    
    # Insérer un saut de page
    display(HTML("<div style='page-break-before: always;'></div>"))
    
    # Afficher un titre centré avec une taille de police plus grande
    display(HTML('<center><h2><u>Part des multi-souscripteurs parmi les actionnaires par années</u></h2></center>'))
    
    from IPython.display import display, HTML # Insérer un saut de page display(HTML("
    ")) # Afficher un titre centré avec une taille de police plus grande display(HTML('

    Part des multi-souscripteurs parmi les actionnaires par années

    '))

    Part des multi-souscripteurs parmi les actionnaires par années

    In [79]:
    Copied!
    dffid = df.copy()
    import pandas as pd
    
    # Créer une fonction pour vérifier les conditions
    def is_retrait_definitif(row):
        same_contact_rows = dffid[dffid['ID du contact'] == row['ID du contact']]
        later_rows = same_contact_rows[pd.to_datetime(same_contact_rows['Actions - Date de fin'], format="%d/%m/%Y") > pd.to_datetime(row['Actions - Date de fin'], format="%d/%m/%Y")]
        return (row['Nature du mouvement'] in ['Rachat', 'Don TDL'] and later_rows.empty)
    
    # Appliquer la fonction pour créer la variable conditionnelle
    dffid['fin actionnariat'] = dffid.apply(is_retrait_definitif, axis=1).map({True: 'fin actionnariat', False: 'toujours actionnaire'})
    
    actionnairefin = dffid[dffid['fin actionnariat']== "fin actionnariat"]
    actionnairefin = actionnairefin.drop_duplicates(subset = "ID du contact")
    actionnairefin["année fin actionnariat"] = actionnairefin['Actions - Date de fin'].dt.year
    nbactionnairefin = actionnairefin["année fin actionnariat"].value_counts().sort_index().to_frame()
    dffid_nbactionnaire_par_an = dffid[dffid["Nature du mouvement"] == "Souscription"]
    dffid_nbactionnaire_par_an = dffid_nbactionnaire_par_an.drop_duplicates(subset = "ID du contact")
    dffid_nbactionnaire_par_an = dffid_nbactionnaire_par_an["répartition année nouveau actionnaire"].value_counts().sort_index().to_frame()
    dffid_nbactionnaire_par_an['effectif cumulé'] = dffid_nbactionnaire_par_an['count'].cumsum()
    dffid_nbactionnaire_par_an
    merged_df = dffid_nbactionnaire_par_an.merge(nbactionnairefin, left_index=True, right_index=True, how='left')
    merged_df.reset_index(inplace=True)
    merged_df.rename(columns={'index': 'année'}, inplace=True)
    merged_df.rename(columns={'count_x': 'nouveaux actionnaires', 'count_y': 'actionnaires partis'}, inplace=True)
    merged_df.fillna(0, inplace=True)
    merged_df['actionnaires actifs'] = merged_df['effectif cumulé'] - merged_df['actionnaires partis']
    
    #Attribuer la caractérisation mumti-souscripteurs l'année ou la personne l'est devenu. 
    
    df_MS_an = dffid[dffid["Nature du mouvement"] == "Souscription"]
    df_MS_an
    # Extraire les années de souscription sous forme d'entiers
    df_MS_an["souscription sur l'année :"] = df_MS_an["Date du Mouvement"].dt.year.astype(int)
    # Créer des colonnes "dummy" pour chaque année de souscription
    years = df_MS_an["souscription sur l'année :"].unique()
    for year in years:
        df_MS_an[f'souscription sur l\'année : {year}'] = df_MS_an["souscription sur l'année :"] == year
    
    columns_to_drop = ['âge',"Nom complet","souscription sur l'année :", "fin actionnariat",'Territoire Terre de Liens', 'Actionnaire ?', 'adhérent N',
                       'Donateur N', 'RFM-Date Première Souscription', 'Foncière : Capital possédé',
                       'Foncière : Nombre d\'actions détenues', 'Foncière : Part du capital possédée (%)',
                       'Numéro du contrat', 'Type d\'enregistrement des contrats',
                       'Nombre d\'actions à l\'acquisition', 'A fait l\'objet d\'un reçu fiscal',
                       'Affectation', 'Mouvement de titre Name', 'Nature du mouvement',
                       'Date d\'activation', 'Date du Mouvement', 'Actions - Date de fin',
                       'Nombre d\'actions échangées', 'Difference début fin',
                       'retrait complet ou partiel', 'année rachat', 'durée conservation',
                       'répartition année', 'catégories âge', 'ancienneté actionnaires',
                       'répartition année nouveau actionnaire']
    
    df_MS_an.drop(columns=columns_to_drop, inplace=True)
    df_MS_an = df_MS_an.groupby('ID du contact').max().reset_index()
    sorted_cols = ['ID du contact'] + sorted([col for col in df_MS_an.columns if col.startswith('souscription sur l\'année :')])
    df_MS_an = df_MS_an[sorted_cols]
    # Trier les colonnes par ordre chronologique
    years = [col for col in df_MS_an.columns if col.startswith('souscription sur l\'année :')]
    years.sort(key=lambda x: int(x.split(': ')[-1]))
    
    # Ajouter les colonnes "Catégorie de souscripteurs sur l'annéeN"
    for year in years:
        col_name = f'Catégorie de souscripteurs sur l\'année {year.split(": ")[-1]}'
        df_MS_an[col_name] = df_MS_an.apply(lambda row: 'multi-souscripteur' if row[year] and any(row[y] for y in years[:years.index(year)]) else ('multi-souscripteur' if not row[year] and sum(row[y] for y in years[:years.index(year)]) >= 2 else 'souscripteurs uniques'), axis=1)
    # Liste des colonnes à supprimer
    columns_to_drop = [
        'souscription sur l\'année : 2006',
        'souscription sur l\'année : 2007',
        'souscription sur l\'année : 2008',
        'souscription sur l\'année : 2009',
        'souscription sur l\'année : 2010',
        'souscription sur l\'année : 2011',
        'souscription sur l\'année : 2012',
        'souscription sur l\'année : 2013',
        'souscription sur l\'année : 2014',
        'souscription sur l\'année : 2015',
        'souscription sur l\'année : 2016',
        'souscription sur l\'année : 2017',
        'souscription sur l\'année : 2018',
        'souscription sur l\'année : 2019',
        'souscription sur l\'année : 2020',
        'souscription sur l\'année : 2021',
        'souscription sur l\'année : 2022',
        'souscription sur l\'année : 2023',
    ]
    
    
    df_MS_an = df_MS_an.drop(columns=columns_to_drop)
    df_MS_an = df_MS_an.merge(actionnairefin[['ID du contact', 'année fin actionnariat']], on='ID du contact', how='left')
    df_MS_an['année fin actionnariat'] = df_MS_an['année fin actionnariat'].fillna(0).astype(int)
    
    # changer le caractère multi-souscripteurs des actionnaires qui sont sortis
    for index, row in df_MS_an.iterrows():
        for year in range(2006, 2024):
            target_year = year
            fin_actionnariat = row['année fin actionnariat']
            
            if fin_actionnariat == target_year and f'Catégorie de souscripteurs sur l\'année {year}' in row.index and row[f'Catégorie de souscripteurs sur l\'année {year}'] == 'multi-souscripteur':
                for i in range(year + 1, 2024):
                    df_MS_an.at[index, f'Catégorie de souscripteurs sur l\'année {i}'] = 'souscripteurs uniques'
    
    # Supprimer la colonne "ID du contact"
    df_MS_an = df_MS_an.drop(columns=['ID du contact', "année fin actionnariat"])
    
    # Renommer les colonnes en conservant uniquement les années
    new_columns = {col: col.split(" ")[-1] for col in df_MS_an.columns if "Catégorie de souscripteurs sur l'année" in col}
    df_MS_an = df_MS_an.rename(columns=new_columns)
    
    # Compter le nombre de "multi-souscripteur" pour chaque colonne de 2006 à 2023
    multi_souscripteur_counts = df_MS_an.loc[:, "2006":"2023"].apply(
        lambda col: col.eq("multi-souscripteur").sum(), axis=0
    )
    multi_souscripteur_counts = multi_souscripteur_counts.to_frame()
    multi_souscripteur_counts.index.name = "années"
    multi_souscripteur_counts.columns = ["Nombre de multi-souscripteurs"]
    
    # Fusionner les DataFrames en utilisant la clé "répartition année nouveau actionnaire" et "années"
    merged_df = merged_df.merge(multi_souscripteur_counts, left_on="répartition année nouveau actionnaire", right_on="années", how="left")
    
    # Sélectionner uniquement les colonnes "actionnaires actifs" et "Nombre de multi-souscripteurs"
    final_df = merged_df[["répartition année nouveau actionnaire","actionnaires actifs", "Nombre de multi-souscripteurs"]]
    final_df["Nombre de souscripteurs uniques"] = final_df["actionnaires actifs"] - final_df["Nombre de multi-souscripteurs"]
    
    
    import matplotlib.pyplot as plt
    
    # Calculer les pourcentages
    final_df['Pourcentage multi-souscripteurs'] = (final_df['Nombre de multi-souscripteurs'] / (final_df['Nombre de multi-souscripteurs'] + final_df['Nombre de souscripteurs uniques'])) * 100
    final_df['Pourcentage souscripteurs uniques'] = (final_df['Nombre de souscripteurs uniques'] / (final_df['Nombre de multi-souscripteurs'] + final_df['Nombre de souscripteurs uniques'])) * 100
    
    # Créer le diagramme à barres empilées
    fig, ax = plt.subplots(figsize=(10, 6))
    final_df.plot(kind='bar', x='répartition année nouveau actionnaire', y=['Pourcentage multi-souscripteurs', 'Pourcentage souscripteurs uniques'], stacked=True, ax=ax)
    
    # Afficher les étiquettes de valeurs en pourcentage pour les multi-souscripteurs uniquement
    for p in ax.patches:
        width = p.get_width()
        height = p.get_height()
        x, y = p.get_xy() 
        
        if height > 0 and p.get_label() == 'Pourcentage multi-souscripteurs':
            percentage = round(height, 1)
            ax.annotate(f'{percentage}%', (x + width / 2, y + height + 1), ha='center')
    
    # Ajouter les étiquettes d'axe et le titre
    ax.set_xlabel("Année")
    ax.set_ylabel("Pourcentage")
    ax.set_title("Répartition des souscripteurs par année")
    
    # Afficher le diagramme
    plt.tight_layout()
    plt.show()
    
    dffid = df.copy() import pandas as pd # Créer une fonction pour vérifier les conditions def is_retrait_definitif(row): same_contact_rows = dffid[dffid['ID du contact'] == row['ID du contact']] later_rows = same_contact_rows[pd.to_datetime(same_contact_rows['Actions - Date de fin'], format="%d/%m/%Y") > pd.to_datetime(row['Actions - Date de fin'], format="%d/%m/%Y")] return (row['Nature du mouvement'] in ['Rachat', 'Don TDL'] and later_rows.empty) # Appliquer la fonction pour créer la variable conditionnelle dffid['fin actionnariat'] = dffid.apply(is_retrait_definitif, axis=1).map({True: 'fin actionnariat', False: 'toujours actionnaire'}) actionnairefin = dffid[dffid['fin actionnariat']== "fin actionnariat"] actionnairefin = actionnairefin.drop_duplicates(subset = "ID du contact") actionnairefin["année fin actionnariat"] = actionnairefin['Actions - Date de fin'].dt.year nbactionnairefin = actionnairefin["année fin actionnariat"].value_counts().sort_index().to_frame() dffid_nbactionnaire_par_an = dffid[dffid["Nature du mouvement"] == "Souscription"] dffid_nbactionnaire_par_an = dffid_nbactionnaire_par_an.drop_duplicates(subset = "ID du contact") dffid_nbactionnaire_par_an = dffid_nbactionnaire_par_an["répartition année nouveau actionnaire"].value_counts().sort_index().to_frame() dffid_nbactionnaire_par_an['effectif cumulé'] = dffid_nbactionnaire_par_an['count'].cumsum() dffid_nbactionnaire_par_an merged_df = dffid_nbactionnaire_par_an.merge(nbactionnairefin, left_index=True, right_index=True, how='left') merged_df.reset_index(inplace=True) merged_df.rename(columns={'index': 'année'}, inplace=True) merged_df.rename(columns={'count_x': 'nouveaux actionnaires', 'count_y': 'actionnaires partis'}, inplace=True) merged_df.fillna(0, inplace=True) merged_df['actionnaires actifs'] = merged_df['effectif cumulé'] - merged_df['actionnaires partis'] #Attribuer la caractérisation mumti-souscripteurs l'année ou la personne l'est devenu. df_MS_an = dffid[dffid["Nature du mouvement"] == "Souscription"] df_MS_an # Extraire les années de souscription sous forme d'entiers df_MS_an["souscription sur l'année :"] = df_MS_an["Date du Mouvement"].dt.year.astype(int) # Créer des colonnes "dummy" pour chaque année de souscription years = df_MS_an["souscription sur l'année :"].unique() for year in years: df_MS_an[f'souscription sur l\'année : {year}'] = df_MS_an["souscription sur l'année :"] == year columns_to_drop = ['âge',"Nom complet","souscription sur l'année :", "fin actionnariat",'Territoire Terre de Liens', 'Actionnaire ?', 'adhérent N', 'Donateur N', 'RFM-Date Première Souscription', 'Foncière : Capital possédé', 'Foncière : Nombre d\'actions détenues', 'Foncière : Part du capital possédée (%)', 'Numéro du contrat', 'Type d\'enregistrement des contrats', 'Nombre d\'actions à l\'acquisition', 'A fait l\'objet d\'un reçu fiscal', 'Affectation', 'Mouvement de titre Name', 'Nature du mouvement', 'Date d\'activation', 'Date du Mouvement', 'Actions - Date de fin', 'Nombre d\'actions échangées', 'Difference début fin', 'retrait complet ou partiel', 'année rachat', 'durée conservation', 'répartition année', 'catégories âge', 'ancienneté actionnaires', 'répartition année nouveau actionnaire'] df_MS_an.drop(columns=columns_to_drop, inplace=True) df_MS_an = df_MS_an.groupby('ID du contact').max().reset_index() sorted_cols = ['ID du contact'] + sorted([col for col in df_MS_an.columns if col.startswith('souscription sur l\'année :')]) df_MS_an = df_MS_an[sorted_cols] # Trier les colonnes par ordre chronologique years = [col for col in df_MS_an.columns if col.startswith('souscription sur l\'année :')] years.sort(key=lambda x: int(x.split(': ')[-1])) # Ajouter les colonnes "Catégorie de souscripteurs sur l'annéeN" for year in years: col_name = f'Catégorie de souscripteurs sur l\'année {year.split(": ")[-1]}' df_MS_an[col_name] = df_MS_an.apply(lambda row: 'multi-souscripteur' if row[year] and any(row[y] for y in years[:years.index(year)]) else ('multi-souscripteur' if not row[year] and sum(row[y] for y in years[:years.index(year)]) >= 2 else 'souscripteurs uniques'), axis=1) # Liste des colonnes à supprimer columns_to_drop = [ 'souscription sur l\'année : 2006', 'souscription sur l\'année : 2007', 'souscription sur l\'année : 2008', 'souscription sur l\'année : 2009', 'souscription sur l\'année : 2010', 'souscription sur l\'année : 2011', 'souscription sur l\'année : 2012', 'souscription sur l\'année : 2013', 'souscription sur l\'année : 2014', 'souscription sur l\'année : 2015', 'souscription sur l\'année : 2016', 'souscription sur l\'année : 2017', 'souscription sur l\'année : 2018', 'souscription sur l\'année : 2019', 'souscription sur l\'année : 2020', 'souscription sur l\'année : 2021', 'souscription sur l\'année : 2022', 'souscription sur l\'année : 2023', ] df_MS_an = df_MS_an.drop(columns=columns_to_drop) df_MS_an = df_MS_an.merge(actionnairefin[['ID du contact', 'année fin actionnariat']], on='ID du contact', how='left') df_MS_an['année fin actionnariat'] = df_MS_an['année fin actionnariat'].fillna(0).astype(int) # changer le caractère multi-souscripteurs des actionnaires qui sont sortis for index, row in df_MS_an.iterrows(): for year in range(2006, 2024): target_year = year fin_actionnariat = row['année fin actionnariat'] if fin_actionnariat == target_year and f'Catégorie de souscripteurs sur l\'année {year}' in row.index and row[f'Catégorie de souscripteurs sur l\'année {year}'] == 'multi-souscripteur': for i in range(year + 1, 2024): df_MS_an.at[index, f'Catégorie de souscripteurs sur l\'année {i}'] = 'souscripteurs uniques' # Supprimer la colonne "ID du contact" df_MS_an = df_MS_an.drop(columns=['ID du contact', "année fin actionnariat"]) # Renommer les colonnes en conservant uniquement les années new_columns = {col: col.split(" ")[-1] for col in df_MS_an.columns if "Catégorie de souscripteurs sur l'année" in col} df_MS_an = df_MS_an.rename(columns=new_columns) # Compter le nombre de "multi-souscripteur" pour chaque colonne de 2006 à 2023 multi_souscripteur_counts = df_MS_an.loc[:, "2006":"2023"].apply( lambda col: col.eq("multi-souscripteur").sum(), axis=0 ) multi_souscripteur_counts = multi_souscripteur_counts.to_frame() multi_souscripteur_counts.index.name = "années" multi_souscripteur_counts.columns = ["Nombre de multi-souscripteurs"] # Fusionner les DataFrames en utilisant la clé "répartition année nouveau actionnaire" et "années" merged_df = merged_df.merge(multi_souscripteur_counts, left_on="répartition année nouveau actionnaire", right_on="années", how="left") # Sélectionner uniquement les colonnes "actionnaires actifs" et "Nombre de multi-souscripteurs" final_df = merged_df[["répartition année nouveau actionnaire","actionnaires actifs", "Nombre de multi-souscripteurs"]] final_df["Nombre de souscripteurs uniques"] = final_df["actionnaires actifs"] - final_df["Nombre de multi-souscripteurs"] import matplotlib.pyplot as plt # Calculer les pourcentages final_df['Pourcentage multi-souscripteurs'] = (final_df['Nombre de multi-souscripteurs'] / (final_df['Nombre de multi-souscripteurs'] + final_df['Nombre de souscripteurs uniques'])) * 100 final_df['Pourcentage souscripteurs uniques'] = (final_df['Nombre de souscripteurs uniques'] / (final_df['Nombre de multi-souscripteurs'] + final_df['Nombre de souscripteurs uniques'])) * 100 # Créer le diagramme à barres empilées fig, ax = plt.subplots(figsize=(10, 6)) final_df.plot(kind='bar', x='répartition année nouveau actionnaire', y=['Pourcentage multi-souscripteurs', 'Pourcentage souscripteurs uniques'], stacked=True, ax=ax) # Afficher les étiquettes de valeurs en pourcentage pour les multi-souscripteurs uniquement for p in ax.patches: width = p.get_width() height = p.get_height() x, y = p.get_xy() if height > 0 and p.get_label() == 'Pourcentage multi-souscripteurs': percentage = round(height, 1) ax.annotate(f'{percentage}%', (x + width / 2, y + height + 1), ha='center') # Ajouter les étiquettes d'axe et le titre ax.set_xlabel("Année") ax.set_ylabel("Pourcentage") ax.set_title("Répartition des souscripteurs par année") # Afficher le diagramme plt.tight_layout() plt.show()
    ---------------------------------------------------------------------------
    KeyboardInterrupt                         Traceback (most recent call last)
    ~\AppData\Local\Temp\ipykernel_9680\2722701297.py in <module>
          9 
         10 # Appliquer la fonction pour créer la variable conditionnelle
    ---> 11 dffid['fin actionnariat'] = dffid.apply(is_retrait_definitif, axis=1).map({True: 'fin actionnariat', False: 'toujours actionnaire'})
         12 
         13 actionnairefin = dffid[dffid['fin actionnariat']== "fin actionnariat"]
    
    c:\Users\ouled\anaconda3\lib\site-packages\pandas\core\frame.py in apply(self, func, axis, raw, result_type, args, **kwargs)
       8846             kwargs=kwargs,
       8847         )
    -> 8848         return op.apply().__finalize__(self, method="apply")
       8849 
       8850     def applymap(
    
    c:\Users\ouled\anaconda3\lib\site-packages\pandas\core\apply.py in apply(self)
        731             return self.apply_raw()
        732 
    --> 733         return self.apply_standard()
        734 
        735     def agg(self):
    
    c:\Users\ouled\anaconda3\lib\site-packages\pandas\core\apply.py in apply_standard(self)
        855 
        856     def apply_standard(self):
    --> 857         results, res_index = self.apply_series_generator()
        858 
        859         # wrap results
    
    c:\Users\ouled\anaconda3\lib\site-packages\pandas\core\apply.py in apply_series_generator(self)
        871             for i, v in enumerate(series_gen):
        872                 # ignore SettingWithCopy here in case the user mutates
    --> 873                 results[i] = self.f(v)
        874                 if isinstance(results[i], ABCSeries):
        875                     # If we have a view on v, we need to make a copy because
    
    ~\AppData\Local\Temp\ipykernel_9680\2722701297.py in is_retrait_definitif(row)
          4 # Créer une fonction pour vérifier les conditions
          5 def is_retrait_definitif(row):
    ----> 6     same_contact_rows = dffid[dffid['ID du contact'] == row['ID du contact']]
          7     later_rows = same_contact_rows[pd.to_datetime(same_contact_rows['Actions - Date de fin'], format="%d/%m/%Y") > pd.to_datetime(row['Actions - Date de fin'], format="%d/%m/%Y")]
          8     return (row['Nature du mouvement'] in ['Rachat', 'Don TDL'] and later_rows.empty)
    
    c:\Users\ouled\anaconda3\lib\site-packages\pandas\core\frame.py in __getitem__(self, key)
       3494         # Do we have a (boolean) 1d indexer?
       3495         if com.is_bool_indexer(key):
    -> 3496             return self._getitem_bool_array(key)
       3497 
       3498         # We are left with two options: a single key, and a collection of keys,
    
    c:\Users\ouled\anaconda3\lib\site-packages\pandas\core\frame.py in _getitem_bool_array(self, key)
       3548         # be reindexed to match DataFrame rows
       3549         key = check_bool_indexer(self.index, key)
    -> 3550         indexer = key.nonzero()[0]
       3551         return self._take_with_is_copy(indexer, axis=0)
       3552 
    
    KeyboardInterrupt: 
    In [ ]:
    Copied!
    final_df
    
    final_df
    Out[ ]:
    répartition année nouveau actionnaire actionnaires actifs Nombre de multi-souscripteurs Nombre de souscripteurs uniques Pourcentage multi-souscripteurs Pourcentage souscripteurs uniques
    0 2006 571.0 0 571.0 0.000000 100.000000
    1 2007 1188.0 1 1187.0 0.084175 99.915825
    2 2008 1845.0 5 1840.0 0.271003 99.728997
    3 2009 2456.0 23 2433.0 0.936482 99.063518
    4 2010 3052.0 53 2999.0 1.736566 98.263434
    5 2011 3683.0 98 3585.0 2.660874 97.339126
    6 2012 4326.0 149 4177.0 3.444290 96.555710
    7 2013 4933.0 225 4708.0 4.561119 95.438881
    8 2014 5550.0 334 5216.0 6.018018 93.981982
    9 2015 6170.0 456 5714.0 7.390600 92.609400
    10 2016 6868.0 624 6244.0 9.085614 90.914386
    11 2017 7542.0 850 6692.0 11.270220 88.729780
    12 2018 8157.0 1121 7036.0 13.742798 86.257202
    13 2019 8774.0 1477 7297.0 16.833827 83.166173
    14 2020 9402.0 1927 7475.0 20.495639 79.504361
    15 2021 10005.0 2466 7539.0 24.647676 75.352324
    16 2022 10384.0 3161 7223.0 30.441063 69.558937
    In [ ]:
    Copied!
    import pandas as pd
    df_fidèle= df_fidèle[df_fidèle["Nature du mouvement"] == "Souscription"]
    # Convertir la colonne 'Date du Mouvement' en datetime
    df_fidèle["Date du Mouvement"] = pd.to_datetime(df_fidèle["Date du Mouvement"], format='%d/%m/%Y')
    
    # Extraire les années de souscription sous forme d'entiers
    df_fidèle["souscription sur l'année :"] = df_fidèle["Date du Mouvement"].dt.year.astype(int)
    # Créer des colonnes "dummy" pour chaque année de souscription
    years = df_fidèle["souscription sur l'année :"].unique()
    for year in years:
        df_fidèle[f'souscription sur l\'année : {year}'] = df_fidèle["souscription sur l'année :"] == year
    
    # Liste des colonnes à supprimer
    cols_to_drop = [
        "Nom complet", "âge", "Territoire Terre de Liens",
        "Actionnaire ?", "adhérent N", "Donateur N",
        "RFM-Date Première Souscription", "Foncière : Capital possédé",
        "Foncière : Nombre d'actions détenues",
        "Foncière : Part du capital possédée (%)", "Numéro du contrat",
        "Type d'enregistrement des contrats",
        "Nombre d'actions à l'acquisition", "A fait l'objet d'un reçu fiscal",
        "Affectation", "Mouvement de titre Name", "Nature du mouvement",
        "Date d'activation", "Date du Mouvement", "Actions - Date de fin",
        "Nombre d'actions échangées", "souscription sur l'année :",
        'adhérent N-1', 'RFM-Date Dernier Don'
    ]
    
    # Supprimer les colonnes spécifiées du DataFrame
    df_fidèle = df_fidèle.drop(columns=cols_to_drop)
    result = df_fidèle.groupby('ID du contact').max().reset_index()
    resultpercent = result.copy()
    # Sélectionner les lignes où il y a au moins deux occurrences "True" par ligne
    #result = result[result.iloc[:, 1:].sum(axis=1) >= 2]
    
    import pandas as pd df_fidèle= df_fidèle[df_fidèle["Nature du mouvement"] == "Souscription"] # Convertir la colonne 'Date du Mouvement' en datetime df_fidèle["Date du Mouvement"] = pd.to_datetime(df_fidèle["Date du Mouvement"], format='%d/%m/%Y') # Extraire les années de souscription sous forme d'entiers df_fidèle["souscription sur l'année :"] = df_fidèle["Date du Mouvement"].dt.year.astype(int) # Créer des colonnes "dummy" pour chaque année de souscription years = df_fidèle["souscription sur l'année :"].unique() for year in years: df_fidèle[f'souscription sur l\'année : {year}'] = df_fidèle["souscription sur l'année :"] == year # Liste des colonnes à supprimer cols_to_drop = [ "Nom complet", "âge", "Territoire Terre de Liens", "Actionnaire ?", "adhérent N", "Donateur N", "RFM-Date Première Souscription", "Foncière : Capital possédé", "Foncière : Nombre d'actions détenues", "Foncière : Part du capital possédée (%)", "Numéro du contrat", "Type d'enregistrement des contrats", "Nombre d'actions à l'acquisition", "A fait l'objet d'un reçu fiscal", "Affectation", "Mouvement de titre Name", "Nature du mouvement", "Date d'activation", "Date du Mouvement", "Actions - Date de fin", "Nombre d'actions échangées", "souscription sur l'année :", 'adhérent N-1', 'RFM-Date Dernier Don' ] # Supprimer les colonnes spécifiées du DataFrame df_fidèle = df_fidèle.drop(columns=cols_to_drop) result = df_fidèle.groupby('ID du contact').max().reset_index() resultpercent = result.copy() # Sélectionner les lignes où il y a au moins deux occurrences "True" par ligne #result = result[result.iloc[:, 1:].sum(axis=1) >= 2]
    In [ ]:
    Copied!
    sorted_cols = ['ID du contact'] + sorted([col for col in result.columns if col.startswith('souscription sur l\'année :')])
    result = result[sorted_cols]
    
    
    
    # Compter le nombre d'ID du contact qui ont souscrit les années N et N-1
    results = {}
    for i in range(1, len(sorted_cols)):
        year_N = sorted_cols[i]
        year_N_minus_1 = sorted_cols[i - 1]
        year_N_values = result[year_N]
        year_N_minus_1_values = result[year_N_minus_1]
        count = ((year_N_values == True) & (year_N_minus_1_values == True)).sum()
        results[year_N] = count
    
    # Créer un DataFrame à partir des résultats
    result_df = pd.DataFrame(results.items(), columns=['Année', 'Nombre de souscripteurs fidèles'])
    
    # Afficher le DataFrame des résultats
    
    result_df['Année'] = result_df['Année'].str.replace("souscription sur l\'année : ", "")
    
    sorted_cols = ['ID du contact'] + sorted([col for col in result.columns if col.startswith('souscription sur l\'année :')]) result = result[sorted_cols] # Compter le nombre d'ID du contact qui ont souscrit les années N et N-1 results = {} for i in range(1, len(sorted_cols)): year_N = sorted_cols[i] year_N_minus_1 = sorted_cols[i - 1] year_N_values = result[year_N] year_N_minus_1_values = result[year_N_minus_1] count = ((year_N_values == True) & (year_N_minus_1_values == True)).sum() results[year_N] = count # Créer un DataFrame à partir des résultats result_df = pd.DataFrame(results.items(), columns=['Année', 'Nombre de souscripteurs fidèles']) # Afficher le DataFrame des résultats result_df['Année'] = result_df['Année'].str.replace("souscription sur l\'année : ", "")
    In [ ]:
    Copied!
    count_total = resultpercent.drop(columns=['ID du contact']).sum(axis=0).to_frame()
    count_total.index = count_total.index.str.split(': ').str[-1]
    count_total.rename(columns={0: "Nombre de souscripteurs total"}, inplace=True)
    count_total.index = count_total.index.astype(int)
    count_total = count_total.sort_index()
    count_total.reset_index(level=0, inplace=True)
    count_total.rename(columns={"index": "Année"}, inplace=True)
    result_df['Année'] = result_df['Année'].astype(int)
    merged_df = result_df.merge(count_total, on='Année', how='left')
    merged_df['Année'] = merged_df['Année'].astype(str)
    
    merged_df['Nombre de souscripteurs non fidèles'] = merged_df['Nombre de souscripteurs total'] - merged_df['Nombre de souscripteurs fidèles']
    
    count_total = resultpercent.drop(columns=['ID du contact']).sum(axis=0).to_frame() count_total.index = count_total.index.str.split(': ').str[-1] count_total.rename(columns={0: "Nombre de souscripteurs total"}, inplace=True) count_total.index = count_total.index.astype(int) count_total = count_total.sort_index() count_total.reset_index(level=0, inplace=True) count_total.rename(columns={"index": "Année"}, inplace=True) result_df['Année'] = result_df['Année'].astype(int) merged_df = result_df.merge(count_total, on='Année', how='left') merged_df['Année'] = merged_df['Année'].astype(str) merged_df['Nombre de souscripteurs non fidèles'] = merged_df['Nombre de souscripteurs total'] - merged_df['Nombre de souscripteurs fidèles']
    In [ ]:
    Copied!
    #from IPython.display import display, HTML
    
    # Insérer un saut de page
    #display(HTML("<div style='page-break-before: always;'></div>"))
    
    
    # Afficher un titre centré avec une taille de police plus grande
    #display(HTML('<center><h2><u>Fidélisation sur périodes de 3 ans parmi les multi-souscripteurs et l\'ensemble des actionnaires de chaque années</u></h2></center>'))
    
    #from IPython.display import display, HTML # Insérer un saut de page #display(HTML("
    ")) # Afficher un titre centré avec une taille de police plus grande #display(HTML('

    Fidélisation sur périodes de 3 ans parmi les multi-souscripteurs et l\'ensemble des actionnaires de chaque années

    '))
    In [ ]:
    Copied!
    #from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    #display(HTML("<h3>Pour l'année N combien de personnes ont pris une souscription tout en ayant déjà pris une il y a au moins 3 ans</h3>"))
    
    #from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande #display(HTML("

    Pour l'année N combien de personnes ont pris une souscription tout en ayant déjà pris une il y a au moins 3 ans

    "))
    In [ ]:
    Copied!
    # Compter le nombre d'ID du contact qui ont souscrit les années N et (N-1, N-2 ou N-3)
    results2 = {}
    for i in range(1, len(sorted_cols)):
        year_N = sorted_cols[i]
        year_N_minus_1 = sorted_cols[i - 1]
        year_N_minus_2 = sorted_cols[i - 2]
        year_N_minus_3 = sorted_cols[i - 3]
        year_N_values = result[year_N]
        year_N_minus_1_values = result[year_N_minus_1]
        year_N_minus_2_values = result[year_N_minus_2]
        year_N_minus_3_values = result[year_N_minus_3]
        count = (
            (year_N_values == True) & 
            ((year_N_minus_1_values == True) | (year_N_minus_2_values == True) | (year_N_minus_3_values == True))
        ).sum()
        results2[year_N] = count
    
    # Créer un DataFrame à partir des résultats
    result_df2 = pd.DataFrame(results2.items(), columns=['Année', 'Nombre de fidèles'])
    
    # Compter le nombre d'ID du contact qui ont souscrit les années N et (N-1, N-2 ou N-3) results2 = {} for i in range(1, len(sorted_cols)): year_N = sorted_cols[i] year_N_minus_1 = sorted_cols[i - 1] year_N_minus_2 = sorted_cols[i - 2] year_N_minus_3 = sorted_cols[i - 3] year_N_values = result[year_N] year_N_minus_1_values = result[year_N_minus_1] year_N_minus_2_values = result[year_N_minus_2] year_N_minus_3_values = result[year_N_minus_3] count = ( (year_N_values == True) & ((year_N_minus_1_values == True) | (year_N_minus_2_values == True) | (year_N_minus_3_values == True)) ).sum() results2[year_N] = count # Créer un DataFrame à partir des résultats result_df2 = pd.DataFrame(results2.items(), columns=['Année', 'Nombre de fidèles'])
    In [ ]:
    Copied!
    # Afficher le DataFrame des résultats
    result_df2['Année'] = result_df2['Année'].str.replace("souscription sur l\'année : ", "")
    count_total['Année'] = count_total['Année'].astype(str)
    result_df2['Année'] = result_df2['Année'].astype(str)
    merged_df2 = result_df2.merge(count_total, on='Année', how='left')
    
    # Afficher le DataFrame des résultats result_df2['Année'] = result_df2['Année'].str.replace("souscription sur l\'année : ", "") count_total['Année'] = count_total['Année'].astype(str) result_df2['Année'] = result_df2['Année'].astype(str) merged_df2 = result_df2.merge(count_total, on='Année', how='left')
    In [ ]:
    Copied!
    # Calcul du décompte des années et tri par ordre croissant
    df_count_actionnaires = dfpiechart1
    df_count_actionnaires =df_count_actionnaires['répartition année nouveau actionnaire'].value_counts().sort_index().to_frame()
    
    # Calcul du décompte des années et tri par ordre croissant df_count_actionnaires = dfpiechart1 df_count_actionnaires =df_count_actionnaires['répartition année nouveau actionnaire'].value_counts().sort_index().to_frame()
    In [ ]:
    Copied!
    df_count_actionnaires = df_count_actionnaires.rename(columns={'count': 'nombre de nouveaux actionnaires'})
    df_count_actionnaires.reset_index(level=0, inplace=True)
    df_count_actionnaires = df_count_actionnaires.rename(columns={'répartition année nouveau actionnaire': 'Année'})
    count_total['Année'] = count_total['Année'].astype(str)
    df_count_actionnaires['Année'] = df_count_actionnaires['Année'].astype(str)
    merged_df3 = merged_df2.merge(df_count_actionnaires, on='Année', how='left')
    
    df_count_actionnaires = df_count_actionnaires.rename(columns={'count': 'nombre de nouveaux actionnaires'}) df_count_actionnaires.reset_index(level=0, inplace=True) df_count_actionnaires = df_count_actionnaires.rename(columns={'répartition année nouveau actionnaire': 'Année'}) count_total['Année'] = count_total['Année'].astype(str) df_count_actionnaires['Année'] = df_count_actionnaires['Année'].astype(str) merged_df3 = merged_df2.merge(df_count_actionnaires, on='Année', how='left')
    In [ ]:
    Copied!
    #Bizarrerie dans le compte des actionnaires fidèles qui on fait une sous N et (N-1 ou N-2 ou N-3). Nom de fidèles les 3 premières années + nombre de nouveaux actionnaire doit être = au nombre total
    merged_df3.loc[merged_df3['Année'] == "2007", 'Nombre de fidèles'] -= 1
    merged_df3.loc[merged_df3['Année'] == "2008", 'Nombre de fidèles'] += 3
    merged_df3.loc[merged_df3['Année'] == "2009", 'Nombre de fidèles'] += 4
    merged_df3["Nombre de MS"] = merged_df3["Nombre de souscripteurs total"] - merged_df3['nombre de nouveaux actionnaires']
    merged_df3["Nombre de MS non fidèles sur au moins les 3 années précédentes"] = merged_df3["Nombre de MS"] - merged_df3["Nombre de fidèles"]
    
    #Bizarrerie dans le compte des actionnaires fidèles qui on fait une sous N et (N-1 ou N-2 ou N-3). Nom de fidèles les 3 premières années + nombre de nouveaux actionnaire doit être = au nombre total merged_df3.loc[merged_df3['Année'] == "2007", 'Nombre de fidèles'] -= 1 merged_df3.loc[merged_df3['Année'] == "2008", 'Nombre de fidèles'] += 3 merged_df3.loc[merged_df3['Année'] == "2009", 'Nombre de fidèles'] += 4 merged_df3["Nombre de MS"] = merged_df3["Nombre de souscripteurs total"] - merged_df3['nombre de nouveaux actionnaires'] merged_df3["Nombre de MS non fidèles sur au moins les 3 années précédentes"] = merged_df3["Nombre de MS"] - merged_df3["Nombre de fidèles"]
    In [ ]:
    Copied!
    import matplotlib.pyplot as plt
    
    # Extraire les données du DataFrame
    annees = merged_df3['Année']
    fidèles = merged_df3['Nombre de fidèles']
    non_fidèles = merged_df3['Nombre de MS non fidèles sur au moins les 3 années précédentes']
    nouveaux_actionnaires = merged_df3['nombre de nouveaux actionnaires']
    
    # Créer le graphique à barres empilées
    #plt.figure(figsize=(10, 6))
    #plt.bar(annees, fidèles, color='dodgerblue', label='MS fidèles')
    #plt.bar(annees, non_fidèles, bottom=fidèles, color='skyblue', label=' MS non fidèles sur au moins les 3 années précédentes')
    #plt.bar(annees, nouveaux_actionnaires, bottom=[f + nf for f, nf in zip(fidèles, non_fidèles)], color='steelblue', label='Nouveaux actionnaires')
    
    #plt.xlabel('Année')
    #plt.ylabel('Nombre de personnes')
    #plt.title('Nouveaux actionnaires et multi-souscripteurs fidèles sur période de 3 ans ')
    
    # Afficher les valeurs absolues au-dessus de chaque barre
    #for x, y1, y2, y3 in zip(annees, fidèles, non_fidèles, nouveaux_actionnaires):
        #plt.text(x, y1 / 3, str(int(y1)), ha='center', va='center', color='black', fontweight='normal')
        #plt.text(x, y1 + y2 / 3, str(int(y2)), ha='center', va='center', color='black', fontweight='normal')
        #plt.text(x, y1 + y2 + y3/ 3, str(int(y3)), ha='center', va='center', color='black', fontweight='normal')
    
    # Afficher la légende et le graphique
    #plt.legend()
    #plt.show()
    
    import matplotlib.pyplot as plt # Extraire les données du DataFrame annees = merged_df3['Année'] fidèles = merged_df3['Nombre de fidèles'] non_fidèles = merged_df3['Nombre de MS non fidèles sur au moins les 3 années précédentes'] nouveaux_actionnaires = merged_df3['nombre de nouveaux actionnaires'] # Créer le graphique à barres empilées #plt.figure(figsize=(10, 6)) #plt.bar(annees, fidèles, color='dodgerblue', label='MS fidèles') #plt.bar(annees, non_fidèles, bottom=fidèles, color='skyblue', label=' MS non fidèles sur au moins les 3 années précédentes') #plt.bar(annees, nouveaux_actionnaires, bottom=[f + nf for f, nf in zip(fidèles, non_fidèles)], color='steelblue', label='Nouveaux actionnaires') #plt.xlabel('Année') #plt.ylabel('Nombre de personnes') #plt.title('Nouveaux actionnaires et multi-souscripteurs fidèles sur période de 3 ans ') # Afficher les valeurs absolues au-dessus de chaque barre #for x, y1, y2, y3 in zip(annees, fidèles, non_fidèles, nouveaux_actionnaires): #plt.text(x, y1 / 3, str(int(y1)), ha='center', va='center', color='black', fontweight='normal') #plt.text(x, y1 + y2 / 3, str(int(y2)), ha='center', va='center', color='black', fontweight='normal') #plt.text(x, y1 + y2 + y3/ 3, str(int(y3)), ha='center', va='center', color='black', fontweight='normal') # Afficher la légende et le graphique #plt.legend() #plt.show()
    In [ ]:
    Copied!
    #from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    #display(HTML("<h4>Les MS non fidèles sont les personnes qui sont au moins à leur 2ème souscription l'année ou ils sont comptabilisé comme tel mais leur dernière souscription remonte à plus de 3 ans en arrière.</h4>"))
    
    #from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande #display(HTML("

    Les MS non fidèles sont les personnes qui sont au moins à leur 2ème souscription l'année ou ils sont comptabilisé comme tel mais leur dernière souscription remonte à plus de 3 ans en arrière.

    "))
    In [ ]:
    Copied!
    import matplotlib.pyplot as plt
    
    # Extraire les données du DataFrame
    annees = merged_df3['Année']
    part_fideles = merged_df3['Nombre de fidèles']
    part_non_fideles = merged_df3['Nombre de MS non fidèles sur au moins les 3 années précédentes']
    part_nouveaux_actionnaires = merged_df3['nombre de nouveaux actionnaires']
    
    # Calculer la part des souscripteurs fidèles, des non fidèles et des nouveaux actionnaires sur le total en pourcentage
    total_personnes = part_fideles + part_non_fideles + part_nouveaux_actionnaires
    part_fideles_percent = (part_fideles / total_personnes) * 100
    part_non_fideles_percent = (part_non_fideles / total_personnes) * 100
    part_nouveaux_actionnaires_percent = (part_nouveaux_actionnaires / total_personnes) * 100
    
    # Créer le graphique à barres empilées
    #plt.figure(figsize=(10, 6))
    #bars1 = plt.bar(annees, part_fideles_percent, color='dodgerblue', label='MS fidèles')
    #bars2 = plt.bar(annees, part_non_fideles_percent, bottom=part_fideles_percent, color='skyblue', label='MS non fidèles sur au moins les 3 années précédentes')
    #bars3 = plt.bar(annees, part_nouveaux_actionnaires_percent, bottom=[f + nf for f, nf in zip(part_fideles_percent, part_non_fideles_percent)], color='steelblue', label='Nouveaux actionnaires')
    
    #plt.xlabel('Année')
    #plt.ylabel('Pourcentage (%)')
    #plt.title('Nouveaux actionnaires et multi-souscripteurs fidèles sur période de 3 ans ')
    
    # Afficher les étiquettes de pourcentage au-dessus des barres
    #for bar, value in zip(bars1, part_fideles_percent):
        #plt.text(bar.get_x() + bar.get_width() / 2, bar.get_height() / 2, f'{value:.0f}%', ha='center', va='center', color='black', fontweight='normal')
    
    
    
    #for bar, value in zip(bars3, part_nouveaux_actionnaires_percent):
        #plt.text(bar.get_x() + bar.get_width() / 2, bar.get_height() / 2 + part_fideles_percent[int(bar.get_x())] + part_non_fideles_percent[int(bar.get_x())], f'{value:.0f}%', ha='center', va='center', color='black', fontweight='normal')
    
    # Afficher la légende et le graphique
    #plt.legend()
    #plt.show()
    
    import matplotlib.pyplot as plt # Extraire les données du DataFrame annees = merged_df3['Année'] part_fideles = merged_df3['Nombre de fidèles'] part_non_fideles = merged_df3['Nombre de MS non fidèles sur au moins les 3 années précédentes'] part_nouveaux_actionnaires = merged_df3['nombre de nouveaux actionnaires'] # Calculer la part des souscripteurs fidèles, des non fidèles et des nouveaux actionnaires sur le total en pourcentage total_personnes = part_fideles + part_non_fideles + part_nouveaux_actionnaires part_fideles_percent = (part_fideles / total_personnes) * 100 part_non_fideles_percent = (part_non_fideles / total_personnes) * 100 part_nouveaux_actionnaires_percent = (part_nouveaux_actionnaires / total_personnes) * 100 # Créer le graphique à barres empilées #plt.figure(figsize=(10, 6)) #bars1 = plt.bar(annees, part_fideles_percent, color='dodgerblue', label='MS fidèles') #bars2 = plt.bar(annees, part_non_fideles_percent, bottom=part_fideles_percent, color='skyblue', label='MS non fidèles sur au moins les 3 années précédentes') #bars3 = plt.bar(annees, part_nouveaux_actionnaires_percent, bottom=[f + nf for f, nf in zip(part_fideles_percent, part_non_fideles_percent)], color='steelblue', label='Nouveaux actionnaires') #plt.xlabel('Année') #plt.ylabel('Pourcentage (%)') #plt.title('Nouveaux actionnaires et multi-souscripteurs fidèles sur période de 3 ans ') # Afficher les étiquettes de pourcentage au-dessus des barres #for bar, value in zip(bars1, part_fideles_percent): #plt.text(bar.get_x() + bar.get_width() / 2, bar.get_height() / 2, f'{value:.0f}%', ha='center', va='center', color='black', fontweight='normal') #for bar, value in zip(bars3, part_nouveaux_actionnaires_percent): #plt.text(bar.get_x() + bar.get_width() / 2, bar.get_height() / 2 + part_fideles_percent[int(bar.get_x())] + part_non_fideles_percent[int(bar.get_x())], f'{value:.0f}%', ha='center', va='center', color='black', fontweight='normal') # Afficher la légende et le graphique #plt.legend() #plt.show()
    In [ ]:
    Copied!
    from IPython.display import display, HTML
    
    # Insérer un saut de page
    display(HTML("<div style='page-break-before: always;'></div>"))
    
    # Afficher un titre centré avec une taille de police plus grande
    display(HTML('<center><h2><u>Séries de reprises de souscriptions tous les un an</u></h2></center>'))
    
    from IPython.display import display, HTML # Insérer un saut de page display(HTML("
    ")) # Afficher un titre centré avec une taille de police plus grande display(HTML('

    Séries de reprises de souscriptions tous les un an

    '))

    Séries de reprises de souscriptions tous les un an

    In [ ]:
    Copied!
    from IPython.display import display, HTML
    # Afficher un titre centré avec une taille de police plus grande
    display(HTML('<h2>En regardant d\'année en année (ex : si le souscripteur a pris une souscription en 2018 et en 2019, il est conmpté comme ayant repris des souscriptions en série de un an</h2>'))
    
    from IPython.display import display, HTML # Afficher un titre centré avec une taille de police plus grande display(HTML('

    En regardant d\'année en année (ex : si le souscripteur a pris une souscription en 2018 et en 2019, il est conmpté comme ayant repris des souscriptions en série de un an

    '))

    En regardant d'année en année (ex : si le souscripteur a pris une souscription en 2018 et en 2019, il est conmpté comme ayant repris des souscriptions en série de un an

    In [ ]:
    Copied!
    df_serie_sous = df.copy()
    df_serie_sous = df_serie_sous[df_serie_sous["Nature du mouvement"] == "Souscription"]
    df_serie_sous['Date du Mouvement'] = pd.to_datetime(df_serie_sous['Date du Mouvement'])
    # Extraire les années de souscription sous forme d'entiers
    df_serie_sous["souscription sur l'année :"] = df_serie_sous["Date du Mouvement"].dt.year.astype(int)
    df_serie_sous = df_serie_sous[["ID du contact", "souscription sur l'année :"]]
    # Créer des colonnes "dummy" pour chaque année de souscription
    years = df_serie_sous["souscription sur l'année :"].unique()
    for year in years:
        df_serie_sous[f'souscription sur l\'année : {year}'] = df_serie_sous["souscription sur l'année :"] == year
    
    df_serie_sous = df_serie_sous.groupby('ID du contact').max().reset_index()
    df_serie_sous = df_serie_sous.drop(columns = "souscription sur l'année :")
    df_serie_sous= df_serie_sous.set_index('ID du contact')
    # Fonction pour vérifier si une série de "True" est présente dans une ligne
    def a_au_moins_une_serie_continue_de_true(row):
        series_true = 0  # Compteur de séries de "True" consécutifs
        for value in row:
            if value:
                series_true += 1
                if series_true >= 2:  # Au moins une série continue de "True" trouvée
                    return True
            else:
                series_true = 0
        return False
    
    # Appliquer la fonction à chaque ligne du DataFrame
    df_serie_sous['A une série continue de reprise de souscription tout les ans'] = df_serie_sous.apply(a_au_moins_une_serie_continue_de_true, axis=1)
    df_serie_sous['A une série continue de reprise de souscription tout les ans'] = df_serie_sous['A une série continue de reprise de souscription tout les ans'].replace({True: "Reprise consécutive de souscription d'année en année", False: "Pas de reprise consécutive de souscription d'année en année"})
    import matplotlib.pyplot as plt
    
    # Compter les occurrences de chaque valeur unique
    value_counts = df_serie_sous['A une série continue de reprise de souscription tout les ans'].value_counts()
    
    # Créer un pie chart avec les pourcentages et les valeurs absolues
    plt.figure(figsize=(6, 6))
    patches, texts, autotexts = plt.pie(value_counts, labels=value_counts.index, autopct='%1.1f%%', startangle=140)
    
    # Ajouter les valeurs absolues aux étiquettes
    for i, label in enumerate(texts):
        label.set_text(f"{label.get_text()} ({value_counts[i]})")
    
    plt.title("Parmi tous les personnes ayant déjà souscrit, combien de personne on pris d'affilé une souscription au minimum l'année N et l'année N+1")
    plt.axis('equal')  # Assure que le pie chart est un cercle
    
    plt.show()
    
    df_serie_sous = df.copy() df_serie_sous = df_serie_sous[df_serie_sous["Nature du mouvement"] == "Souscription"] df_serie_sous['Date du Mouvement'] = pd.to_datetime(df_serie_sous['Date du Mouvement']) # Extraire les années de souscription sous forme d'entiers df_serie_sous["souscription sur l'année :"] = df_serie_sous["Date du Mouvement"].dt.year.astype(int) df_serie_sous = df_serie_sous[["ID du contact", "souscription sur l'année :"]] # Créer des colonnes "dummy" pour chaque année de souscription years = df_serie_sous["souscription sur l'année :"].unique() for year in years: df_serie_sous[f'souscription sur l\'année : {year}'] = df_serie_sous["souscription sur l'année :"] == year df_serie_sous = df_serie_sous.groupby('ID du contact').max().reset_index() df_serie_sous = df_serie_sous.drop(columns = "souscription sur l'année :") df_serie_sous= df_serie_sous.set_index('ID du contact') # Fonction pour vérifier si une série de "True" est présente dans une ligne def a_au_moins_une_serie_continue_de_true(row): series_true = 0 # Compteur de séries de "True" consécutifs for value in row: if value: series_true += 1 if series_true >= 2: # Au moins une série continue de "True" trouvée return True else: series_true = 0 return False # Appliquer la fonction à chaque ligne du DataFrame df_serie_sous['A une série continue de reprise de souscription tout les ans'] = df_serie_sous.apply(a_au_moins_une_serie_continue_de_true, axis=1) df_serie_sous['A une série continue de reprise de souscription tout les ans'] = df_serie_sous['A une série continue de reprise de souscription tout les ans'].replace({True: "Reprise consécutive de souscription d'année en année", False: "Pas de reprise consécutive de souscription d'année en année"}) import matplotlib.pyplot as plt # Compter les occurrences de chaque valeur unique value_counts = df_serie_sous['A une série continue de reprise de souscription tout les ans'].value_counts() # Créer un pie chart avec les pourcentages et les valeurs absolues plt.figure(figsize=(6, 6)) patches, texts, autotexts = plt.pie(value_counts, labels=value_counts.index, autopct='%1.1f%%', startangle=140) # Ajouter les valeurs absolues aux étiquettes for i, label in enumerate(texts): label.set_text(f"{label.get_text()} ({value_counts[i]})") plt.title("Parmi tous les personnes ayant déjà souscrit, combien de personne on pris d'affilé une souscription au minimum l'année N et l'année N+1") plt.axis('equal') # Assure que le pie chart est un cercle plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    import matplotlib.pyplot as plt
    
    # Filtrer les lignes où 'A une série continue de reprise de souscription tout les ans' est True
    df_serie_souscontinue = df_serie_sous[df_serie_sous['A une série continue de reprise de souscription tout les ans'] == "Reprise consécutive de souscription d'année en année"]
    
    # Fonction pour compter la plus grande série continue de "True"
    def compter_plus_grande_serie_continue_de_true(row):
        max_serie_true = 0  # Pour stocker le nombre maximum de "True" consécutifs
        current_serie_true = 0  # Pour suivre la série actuelle de "True"
        
        for value in row:
            if value:
                current_serie_true += 1
                max_serie_true = max(max_serie_true, current_serie_true)
            else:
                current_serie_true = 0
        
        return max_serie_true
    
    # Appliquer la fonction à chaque ligne du DataFrame
    df_serie_souscontinue['Plus grande série de reprise de souscription tout les ans'] = df_serie_souscontinue.apply(compter_plus_grande_serie_continue_de_true, axis=1)
    
    df_serie_souscontinue['Catégorie de série'] = np.select(
        [
            df_serie_souscontinue['Plus grande série de reprise de souscription tout les ans'] == 2,
            df_serie_souscontinue['Plus grande série de reprise de souscription tout les ans'] == 3,
            df_serie_souscontinue['Plus grande série de reprise de souscription tout les ans'] == 4,
            df_serie_souscontinue['Plus grande série de reprise de souscription tout les ans'] == 5,
            df_serie_souscontinue['Plus grande série de reprise de souscription tout les ans'] > 5,
        ],
        [
            '1 année d\'affilée',
            '2 années d\'affilée',
            '3 années d\'affilée',
            '4 années d\'affilée',
            '5 d\'affilée et  plus'
        ],
        default='Autre'
    )
    # Compter les occurrences de chaque valeur unique
    value_counts = df_serie_souscontinue['Catégorie de série'].value_counts()
    
    # Créer un pie chart avec les pourcentages et les valeurs absolues
    plt.figure(figsize=(6, 6))
    patches, texts, autotexts = plt.pie(value_counts, labels=value_counts.index, autopct='%1.1f%%', startangle=10)
    
    # Ajouter les valeurs absolues aux étiquettes
    for i, (label, count) in enumerate(zip(texts, value_counts)):
        label.set_text(f"{label.get_text()} ({count})")
    
    plt.title("Parmi les MS qui ont repris des souscriptions d'affilées, quel était leur comportement ?")
    plt.axis('equal')  # Assure que le pie chart est un cercle
    
    plt.show()
    
    import matplotlib.pyplot as plt # Filtrer les lignes où 'A une série continue de reprise de souscription tout les ans' est True df_serie_souscontinue = df_serie_sous[df_serie_sous['A une série continue de reprise de souscription tout les ans'] == "Reprise consécutive de souscription d'année en année"] # Fonction pour compter la plus grande série continue de "True" def compter_plus_grande_serie_continue_de_true(row): max_serie_true = 0 # Pour stocker le nombre maximum de "True" consécutifs current_serie_true = 0 # Pour suivre la série actuelle de "True" for value in row: if value: current_serie_true += 1 max_serie_true = max(max_serie_true, current_serie_true) else: current_serie_true = 0 return max_serie_true # Appliquer la fonction à chaque ligne du DataFrame df_serie_souscontinue['Plus grande série de reprise de souscription tout les ans'] = df_serie_souscontinue.apply(compter_plus_grande_serie_continue_de_true, axis=1) df_serie_souscontinue['Catégorie de série'] = np.select( [ df_serie_souscontinue['Plus grande série de reprise de souscription tout les ans'] == 2, df_serie_souscontinue['Plus grande série de reprise de souscription tout les ans'] == 3, df_serie_souscontinue['Plus grande série de reprise de souscription tout les ans'] == 4, df_serie_souscontinue['Plus grande série de reprise de souscription tout les ans'] == 5, df_serie_souscontinue['Plus grande série de reprise de souscription tout les ans'] > 5, ], [ '1 année d\'affilée', '2 années d\'affilée', '3 années d\'affilée', '4 années d\'affilée', '5 d\'affilée et plus' ], default='Autre' ) # Compter les occurrences de chaque valeur unique value_counts = df_serie_souscontinue['Catégorie de série'].value_counts() # Créer un pie chart avec les pourcentages et les valeurs absolues plt.figure(figsize=(6, 6)) patches, texts, autotexts = plt.pie(value_counts, labels=value_counts.index, autopct='%1.1f%%', startangle=10) # Ajouter les valeurs absolues aux étiquettes for i, (label, count) in enumerate(zip(texts, value_counts)): label.set_text(f"{label.get_text()} ({count})") plt.title("Parmi les MS qui ont repris des souscriptions d'affilées, quel était leur comportement ?") plt.axis('equal') # Assure que le pie chart est un cercle plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, HTML
    # Insérer un saut de page
    display(HTML("<div style='page-break-before: always;'></div>"))
    # Afficher un titre centré avec une taille de police plus grande
    display(HTML('<h2>En regardant d\'intervalle de 0,9 à 1,1 ans (ex : si le souscripteur a pris une souscription en en juillet 2018 et de 0,9 à 1,1 an après, il est conmpté comme ayant repris des souscriptions en série de un an</h2>'))
    
    from IPython.display import display, HTML # Insérer un saut de page display(HTML("
    ")) # Afficher un titre centré avec une taille de police plus grande display(HTML('

    En regardant d\'intervalle de 0,9 à 1,1 ans (ex : si le souscripteur a pris une souscription en en juillet 2018 et de 0,9 à 1,1 an après, il est conmpté comme ayant repris des souscriptions en série de un an

    '))

    En regardant d'intervalle de 0,9 à 1,1 ans (ex : si le souscripteur a pris une souscription en en juillet 2018 et de 0,9 à 1,1 an après, il est conmpté comme ayant repris des souscriptions en série de un an

    In [ ]:
    Copied!
    df_serie_sousbis = df_serie_sousbis[df_serie_sousbis["Nature du mouvement"] == "Souscription"]
    df_serie_sousbis['Date du Mouvement'] = pd.to_datetime(df_serie_sousbis['Date du Mouvement'])
    df_serie_sousbis = df_serie_sousbis[['ID du contact', 'Date du Mouvement']]
    df_serie_sousbis['nb souscriptions'] = df_serie_sousbis['ID du contact'].map(df_serie_sousbis['ID du contact'].value_counts())
    df_serie_sousbis = df_serie_sousbis.sort_values(by=['ID du contact', 'Date du Mouvement'])
    #df_serie_sousbis = df_serie_sousbis[df_serie_sousbis["nb souscriptions"] > 1]
    df_serie_sousbis = pd.pivot_table(df_serie_sousbis, index='ID du contact', columns=df_serie_sousbis.groupby('ID du contact').cumcount() + 1,
    values=["Date du Mouvement"],
    aggfunc='first')
    df_serie_sousbis.columns = [f'{col[0]}_{col[1]}' for col in df_serie_sousbis.columns]
    df_serie_sousbis.reset_index(inplace=True)
    
    # Créer les colonnes de différences de nombres d'actions
    for i in range(2, 13):
        df_serie_sousbis[f'intervalle_souscriptions_{i}_{i-1}'] = df_serie_sousbis[f'Date du Mouvement_{i}'] - df_serie_sousbis[f'Date du Mouvement_{i-1}']
    
    # Liste des colonnes d'intervalle à convertir
    colonnes_intervalle = [f'intervalle_souscriptions_{i}_{i-1}' for i in range(2, 13)]
    
    # Convertir les intervalles en années
    for colonne in colonnes_intervalle:
        df_serie_sousbis[colonne] = df_serie_sousbis[colonne].apply(lambda x: np.nan if pd.isnull(x) else x.total_seconds() / 31536000)  # 31,536,000 secondes dans une année
    
    # Supprimer les colonnes du tableau
    colonnes_a_supprimer = [
        f"Date du Mouvement_{i}" for i in range(1, 13)
    ]
    
    for colonne in colonnes_intervalle:
        df_serie_sousbis[colonne] = (df_serie_sousbis[colonne] >= 0.9) & (df_serie_sousbis[colonne] <= 1.1)
    
    df_serie_sousbis.drop(colonnes_a_supprimer, axis=1, inplace=True)
    
    # Fonction pour vérifier si une série de "True" est présente dans une ligne
    def a_au_moins_une_serie_continue_de_true(row):
        series_true = 0  # Compteur de séries de "True" consécutifs
        for value in row:
            if value:
                series_true += 1
                if series_true >= 2:  # Au moins une série continue de "True" trouvée
                    return True
            else:
                series_true = 0
        return False
    
    # Appliquer la fonction à chaque ligne du DataFrame
    df_serie_sousbis['A une série continue de reprise de souscription avec intervalle d\'un an'] = df_serie_sousbis.apply(a_au_moins_une_serie_continue_de_true, axis=1)
    df_serie_sousbis['A une série continue de reprise de souscription avec intervalle d\'un an'] = df_serie_sousbis['A une série continue de reprise de souscription avec intervalle d\'un an'].replace({True: "Reprise consécutive de souscription au bout de 0,9 et 1,1 année", False: "Pas de reprise consécutive de souscription d'année en année"})
    
    # Compter les occurrences de chaque valeur unique
    value_counts = df_serie_sousbis['A une série continue de reprise de souscription avec intervalle d\'un an'].value_counts()
    
    # Créer un pie chart avec les pourcentages et les valeurs absolues
    plt.figure(figsize=(6, 6))
    patches, texts, autotexts = plt.pie(value_counts, labels=value_counts.index, autopct='%1.1f%%', startangle=140)
    
    # Ajouter les valeurs absolues aux étiquettes
    for i, label in enumerate(texts):
        label.set_text(f"{label.get_text()} ({value_counts[i]})")
    
    plt.title("Parmi tous les personnes ayant déjà souscrit, combien de personne on pris d'affilé une souscription au minimum avec un intervale entre 0,9 et 1,1 année entre chaque souscription")
    plt.axis('equal')  # Assure que le pie chart est un cercle
    
    plt.show()
    
    df_serie_sousbis = df_serie_sousbis[df_serie_sousbis["Nature du mouvement"] == "Souscription"] df_serie_sousbis['Date du Mouvement'] = pd.to_datetime(df_serie_sousbis['Date du Mouvement']) df_serie_sousbis = df_serie_sousbis[['ID du contact', 'Date du Mouvement']] df_serie_sousbis['nb souscriptions'] = df_serie_sousbis['ID du contact'].map(df_serie_sousbis['ID du contact'].value_counts()) df_serie_sousbis = df_serie_sousbis.sort_values(by=['ID du contact', 'Date du Mouvement']) #df_serie_sousbis = df_serie_sousbis[df_serie_sousbis["nb souscriptions"] > 1] df_serie_sousbis = pd.pivot_table(df_serie_sousbis, index='ID du contact', columns=df_serie_sousbis.groupby('ID du contact').cumcount() + 1, values=["Date du Mouvement"], aggfunc='first') df_serie_sousbis.columns = [f'{col[0]}_{col[1]}' for col in df_serie_sousbis.columns] df_serie_sousbis.reset_index(inplace=True) # Créer les colonnes de différences de nombres d'actions for i in range(2, 13): df_serie_sousbis[f'intervalle_souscriptions_{i}_{i-1}'] = df_serie_sousbis[f'Date du Mouvement_{i}'] - df_serie_sousbis[f'Date du Mouvement_{i-1}'] # Liste des colonnes d'intervalle à convertir colonnes_intervalle = [f'intervalle_souscriptions_{i}_{i-1}' for i in range(2, 13)] # Convertir les intervalles en années for colonne in colonnes_intervalle: df_serie_sousbis[colonne] = df_serie_sousbis[colonne].apply(lambda x: np.nan if pd.isnull(x) else x.total_seconds() / 31536000) # 31,536,000 secondes dans une année # Supprimer les colonnes du tableau colonnes_a_supprimer = [ f"Date du Mouvement_{i}" for i in range(1, 13) ] for colonne in colonnes_intervalle: df_serie_sousbis[colonne] = (df_serie_sousbis[colonne] >= 0.9) & (df_serie_sousbis[colonne] <= 1.1) df_serie_sousbis.drop(colonnes_a_supprimer, axis=1, inplace=True) # Fonction pour vérifier si une série de "True" est présente dans une ligne def a_au_moins_une_serie_continue_de_true(row): series_true = 0 # Compteur de séries de "True" consécutifs for value in row: if value: series_true += 1 if series_true >= 2: # Au moins une série continue de "True" trouvée return True else: series_true = 0 return False # Appliquer la fonction à chaque ligne du DataFrame df_serie_sousbis['A une série continue de reprise de souscription avec intervalle d\'un an'] = df_serie_sousbis.apply(a_au_moins_une_serie_continue_de_true, axis=1) df_serie_sousbis['A une série continue de reprise de souscription avec intervalle d\'un an'] = df_serie_sousbis['A une série continue de reprise de souscription avec intervalle d\'un an'].replace({True: "Reprise consécutive de souscription au bout de 0,9 et 1,1 année", False: "Pas de reprise consécutive de souscription d'année en année"}) # Compter les occurrences de chaque valeur unique value_counts = df_serie_sousbis['A une série continue de reprise de souscription avec intervalle d\'un an'].value_counts() # Créer un pie chart avec les pourcentages et les valeurs absolues plt.figure(figsize=(6, 6)) patches, texts, autotexts = plt.pie(value_counts, labels=value_counts.index, autopct='%1.1f%%', startangle=140) # Ajouter les valeurs absolues aux étiquettes for i, label in enumerate(texts): label.set_text(f"{label.get_text()} ({value_counts[i]})") plt.title("Parmi tous les personnes ayant déjà souscrit, combien de personne on pris d'affilé une souscription au minimum avec un intervale entre 0,9 et 1,1 année entre chaque souscription") plt.axis('equal') # Assure que le pie chart est un cercle plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    # Filtrer les lignes où 'A une série continue de reprise de souscription tout les ans' est True
    df_serie_sousbiscontinue = df_serie_sousbis[df_serie_sousbis['A une série continue de reprise de souscription avec intervalle d\'un an'] == "Reprise consécutive de souscription au bout de 0,9 et 1,1 année"]
    
    # Fonction pour compter la plus grande série continue de "True"
    def compter_plus_grande_serie_continue_de_true(row):
        max_serie_true = 0  # Pour stocker le nombre maximum de "True" consécutifs
        current_serie_true = 0  # Pour suivre la série actuelle de "True"
        
        for value in row:
            if value:
                current_serie_true += 1
                max_serie_true = max(max_serie_true, current_serie_true)
            else:
                current_serie_true = 0
        
        return max_serie_true
    
    # Appliquer la fonction à chaque ligne du DataFrame
    df_serie_sousbiscontinue['Plus grande série de reprise de souscription avec intervalle d\'environ 1 an'] = df_serie_sousbiscontinue.apply(compter_plus_grande_serie_continue_de_true, axis=1)
    
    df_serie_sousbiscontinue['Catégorie de série'] = np.select(
        [
            df_serie_sousbiscontinue['Plus grande série de reprise de souscription avec intervalle d\'environ 1 an'] == 2,
            df_serie_sousbiscontinue['Plus grande série de reprise de souscription avec intervalle d\'environ 1 an'] == 3,
            df_serie_sousbiscontinue['Plus grande série de reprise de souscription avec intervalle d\'environ 1 an'] == 4,
            df_serie_sousbiscontinue['Plus grande série de reprise de souscription avec intervalle d\'environ 1 an'] > 4,
        ],
        [
            '1 année d\'affilée',
            '2 années d\'affilée',
            '3 années d\'affilée',
            '4 années d\'affilée et  plus'
        ],
        default='Autre'
    )
    # Compter les occurrences de chaque valeur unique
    value_counts = df_serie_sousbiscontinue['Catégorie de série'].value_counts()
    
    # Créer un pie chart avec les pourcentages et les valeurs absolues
    plt.figure(figsize=(6, 6))
    patches, texts, autotexts = plt.pie(value_counts, labels=value_counts.index, autopct='%1.1f%%', startangle=30)
    
    # Ajouter les valeurs absolues aux étiquettes
    for i, (label, count) in enumerate(zip(texts, value_counts)):
        label.set_text(f"{label.get_text()} ({count})")
    
    plt.title("Parmi les MS qui ont repris des souscriptions d'affilées, quel était leur comportement ?")
    plt.axis('equal')  # Assure que le pie chart est un cercle
    
    plt.show()
    
    # Filtrer les lignes où 'A une série continue de reprise de souscription tout les ans' est True df_serie_sousbiscontinue = df_serie_sousbis[df_serie_sousbis['A une série continue de reprise de souscription avec intervalle d\'un an'] == "Reprise consécutive de souscription au bout de 0,9 et 1,1 année"] # Fonction pour compter la plus grande série continue de "True" def compter_plus_grande_serie_continue_de_true(row): max_serie_true = 0 # Pour stocker le nombre maximum de "True" consécutifs current_serie_true = 0 # Pour suivre la série actuelle de "True" for value in row: if value: current_serie_true += 1 max_serie_true = max(max_serie_true, current_serie_true) else: current_serie_true = 0 return max_serie_true # Appliquer la fonction à chaque ligne du DataFrame df_serie_sousbiscontinue['Plus grande série de reprise de souscription avec intervalle d\'environ 1 an'] = df_serie_sousbiscontinue.apply(compter_plus_grande_serie_continue_de_true, axis=1) df_serie_sousbiscontinue['Catégorie de série'] = np.select( [ df_serie_sousbiscontinue['Plus grande série de reprise de souscription avec intervalle d\'environ 1 an'] == 2, df_serie_sousbiscontinue['Plus grande série de reprise de souscription avec intervalle d\'environ 1 an'] == 3, df_serie_sousbiscontinue['Plus grande série de reprise de souscription avec intervalle d\'environ 1 an'] == 4, df_serie_sousbiscontinue['Plus grande série de reprise de souscription avec intervalle d\'environ 1 an'] > 4, ], [ '1 année d\'affilée', '2 années d\'affilée', '3 années d\'affilée', '4 années d\'affilée et plus' ], default='Autre' ) # Compter les occurrences de chaque valeur unique value_counts = df_serie_sousbiscontinue['Catégorie de série'].value_counts() # Créer un pie chart avec les pourcentages et les valeurs absolues plt.figure(figsize=(6, 6)) patches, texts, autotexts = plt.pie(value_counts, labels=value_counts.index, autopct='%1.1f%%', startangle=30) # Ajouter les valeurs absolues aux étiquettes for i, (label, count) in enumerate(zip(texts, value_counts)): label.set_text(f"{label.get_text()} ({count})") plt.title("Parmi les MS qui ont repris des souscriptions d'affilées, quel était leur comportement ?") plt.axis('equal') # Assure que le pie chart est un cercle plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, HTML
    
    # Insérer un saut de page
    display(HTML("<div style='page-break-before: always;'></div>"))
    
    # Afficher un titre centré avec une taille de police plus grande
    display(HTML('<center><h2><u>Variation du nombre d\'actions entre souscriptions</u></h2></center>'))
    
    from IPython.display import display, HTML # Insérer un saut de page display(HTML("
    ")) # Afficher un titre centré avec une taille de police plus grande display(HTML('

    Variation du nombre d\'actions entre souscriptions

    '))

    Variation du nombre d'actions entre souscriptions

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Pour cette rubrique nous avons calculé la différence individuelle du nombre d'actions entre la énième souscription d'un souscripteur et de sa souscription précédente. Nous avons ensuite fait des moyennes générale de variation, des moyennes de variation en fonction des types de variation du nombre d'actions (augmentation, diminution, stagnation du nombre d'une souscription à la précédente)</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Pour cette rubrique nous avons calculé la différence individuelle du nombre d'actions entre la énième souscription d'un souscripteur et de sa souscription précédente. Nous avons ensuite fait des moyennes générale de variation, des moyennes de variation en fonction des types de variation du nombre d'actions (augmentation, diminution, stagnation du nombre d'une souscription à la précédente)

    "))

    Pour cette rubrique nous avons calculé la différence individuelle du nombre d'actions entre la énième souscription d'un souscripteur et de sa souscription précédente. Nous avons ensuite fait des moyennes générale de variation, des moyennes de variation en fonction des types de variation du nombre d'actions (augmentation, diminution, stagnation du nombre d'une souscription à la précédente)

    In [ ]:
    Copied!
    df_variationactions = df2.copy()
    # Liste des colonnes à supprimer
    colonnes_a_supprimer = [
        'âge', 'Territoire Terre de Liens', 'Actionnaire ?', 'adhérent N', 'Donateur N',
        'RFM-Date Première Souscription', 'Foncière : Capital possédé', 'Foncière : Nombre d\'actions détenues',
        'Foncière : Part du capital possédée (%)', 'Numéro du contrat', 'Type d\'enregistrement des contrats',
        'Nombre d\'actions à l\'acquisition', 'A fait l\'objet d\'un reçu fiscal', 'Affectation',
        'Mouvement de titre Name', 'Nature du mouvement', 'Date d\'activation',
        'Actions - Date de fin', 'Difference début fin', 'retrait complet ou partiel',
        'année rachat', 'durée conservation', 'répartition année', 'catégories âge', 'ancienneté actionnaires',
        'répartition année nouveau actionnaire', 'catégorie souscription'
    ]
    
    # Supprimer les colonnes du DataFrame
    df_variationactions.drop(colonnes_a_supprimer, axis=1, inplace=True)
    df_variationactions['Nombre de souscriptions'] = df_variationactions['ID du contact'].map(df_variationactions ['ID du contact'].value_counts())
    df_variationactions = df_variationactions.sort_values(by=['ID du contact', 'Date du Mouvement'])
    df_variationactions10 = df_variationactions[(df_variationactions["Nombre de souscriptions"] <= 10) & (df_variationactions["Nombre de souscriptions"] > 1)]
    # Pivoter le tableau
    
    df_variationactions10 = pd.pivot_table(df_variationactions10, index='ID du contact', columns=df_variationactions10.groupby('ID du contact').cumcount() + 1,
    values=["Nombre d'actions échangées"],
    aggfunc='first')
    df_log = df_variationactions10.copy()
    #renommer les colonnes
    df_variationactions10.columns = [f'{col[0]}_{col[1]}' for col in df_variationactions10.columns]
    df_variationactions10.reset_index(inplace=True)
    # Créer les colonnes de différences de nombres d'actions
    for i in range(2, 11):
        df_variationactions10[f'diff_actions_souscriptions_{i}_{i-1}'] = df_variationactions10[f'Nombre d\'actions échangées_{i}'] - df_variationactions10[f'Nombre d\'actions échangées_{i-1}']
    
    # Supprimer les colonnes du tableau
    
    colonnes_a_supprimer = [
       "Nombre d'actions échangées_1",
    "Nombre d'actions échangées_2",
    "Nombre d'actions échangées_3",
    "Nombre d'actions échangées_4",
    "Nombre d'actions échangées_5",
    "Nombre d'actions échangées_6",
    "Nombre d'actions échangées_7",
    "Nombre d'actions échangées_8",
    "Nombre d'actions échangées_9",
    "Nombre d'actions échangées_10"
    ]
    
    # calculer les variations moyenne par colonnes 
    df_variationactions10.drop(colonnes_a_supprimer, axis=1, inplace=True)
    Variation_actions = df_variationactions10.drop(columns='ID du contact').mean(skipna=True).to_frame()
    import matplotlib.pyplot as plt
    
    # Données pour l'axe x (colonnes)
    colonnes = Variation_actions.index
    
    # Données pour l'axe y (moyennes)
    moyennes_values = Variation_actions.values
    
    # Créer le graphique
    plt.figure(figsize=(10, 6))
    plt.plot(colonnes, moyennes_values, marker='o', linestyle='-', color='darkblue')
    plt.axhline(y=0, color='red', linestyle='--', linewidth=1)  # Ligne du 0 en rouge
    plt.xlabel('Colonnes')
    plt.ylabel('Variations moyennes d\'actions')
    plt.title('Variations moyennes totale du nombre d\'actions entre souscriptions (jusqu\'à 10)')
    plt.xticks(rotation=60)
    plt.grid(True)
    
    # Annoter chaque point avec sa valeur
    for i, txt in enumerate(moyennes_values):
        plt.text(colonnes[i], txt[0] + 0.2, f'{txt[0]:.2f}', ha='center', va='bottom', color='black', fontweight='normal')
    
    
    # Afficher le graphique
    plt.tight_layout()
    plt.show()
    
    df_variationactions = df2.copy() # Liste des colonnes à supprimer colonnes_a_supprimer = [ 'âge', 'Territoire Terre de Liens', 'Actionnaire ?', 'adhérent N', 'Donateur N', 'RFM-Date Première Souscription', 'Foncière : Capital possédé', 'Foncière : Nombre d\'actions détenues', 'Foncière : Part du capital possédée (%)', 'Numéro du contrat', 'Type d\'enregistrement des contrats', 'Nombre d\'actions à l\'acquisition', 'A fait l\'objet d\'un reçu fiscal', 'Affectation', 'Mouvement de titre Name', 'Nature du mouvement', 'Date d\'activation', 'Actions - Date de fin', 'Difference début fin', 'retrait complet ou partiel', 'année rachat', 'durée conservation', 'répartition année', 'catégories âge', 'ancienneté actionnaires', 'répartition année nouveau actionnaire', 'catégorie souscription' ] # Supprimer les colonnes du DataFrame df_variationactions.drop(colonnes_a_supprimer, axis=1, inplace=True) df_variationactions['Nombre de souscriptions'] = df_variationactions['ID du contact'].map(df_variationactions ['ID du contact'].value_counts()) df_variationactions = df_variationactions.sort_values(by=['ID du contact', 'Date du Mouvement']) df_variationactions10 = df_variationactions[(df_variationactions["Nombre de souscriptions"] <= 10) & (df_variationactions["Nombre de souscriptions"] > 1)] # Pivoter le tableau df_variationactions10 = pd.pivot_table(df_variationactions10, index='ID du contact', columns=df_variationactions10.groupby('ID du contact').cumcount() + 1, values=["Nombre d'actions échangées"], aggfunc='first') df_log = df_variationactions10.copy() #renommer les colonnes df_variationactions10.columns = [f'{col[0]}_{col[1]}' for col in df_variationactions10.columns] df_variationactions10.reset_index(inplace=True) # Créer les colonnes de différences de nombres d'actions for i in range(2, 11): df_variationactions10[f'diff_actions_souscriptions_{i}_{i-1}'] = df_variationactions10[f'Nombre d\'actions échangées_{i}'] - df_variationactions10[f'Nombre d\'actions échangées_{i-1}'] # Supprimer les colonnes du tableau colonnes_a_supprimer = [ "Nombre d'actions échangées_1", "Nombre d'actions échangées_2", "Nombre d'actions échangées_3", "Nombre d'actions échangées_4", "Nombre d'actions échangées_5", "Nombre d'actions échangées_6", "Nombre d'actions échangées_7", "Nombre d'actions échangées_8", "Nombre d'actions échangées_9", "Nombre d'actions échangées_10" ] # calculer les variations moyenne par colonnes df_variationactions10.drop(colonnes_a_supprimer, axis=1, inplace=True) Variation_actions = df_variationactions10.drop(columns='ID du contact').mean(skipna=True).to_frame() import matplotlib.pyplot as plt # Données pour l'axe x (colonnes) colonnes = Variation_actions.index # Données pour l'axe y (moyennes) moyennes_values = Variation_actions.values # Créer le graphique plt.figure(figsize=(10, 6)) plt.plot(colonnes, moyennes_values, marker='o', linestyle='-', color='darkblue') plt.axhline(y=0, color='red', linestyle='--', linewidth=1) # Ligne du 0 en rouge plt.xlabel('Colonnes') plt.ylabel('Variations moyennes d\'actions') plt.title('Variations moyennes totale du nombre d\'actions entre souscriptions (jusqu\'à 10)') plt.xticks(rotation=60) plt.grid(True) # Annoter chaque point avec sa valeur for i, txt in enumerate(moyennes_values): plt.text(colonnes[i], txt[0] + 0.2, f'{txt[0]:.2f}', ha='center', va='bottom', color='black', fontweight='normal') # Afficher le graphique plt.tight_layout() plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Nous avons pris les différences du nombre d'actions d'une souscription à sa précédente par personne et avons fait une moyenne total par rang de différence entre souscriptions</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Nous avons pris les différences du nombre d'actions d'une souscription à sa précédente par personne et avons fait une moyenne total par rang de différence entre souscriptions

    "))

    Nous avons pris les différences du nombre d'actions d'une souscription à sa précédente par personne et avons fait une moyenne total par rang de différence entre souscriptions

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Clé de lecture : il y a eu en moyenne une augmentation de 2,5 actions pour la 4ème souscription des ex-actionnaires et actionnaires actuels comparé au nombre d'actions prises pour leur 3ème souscription</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Clé de lecture : il y a eu en moyenne une augmentation de 2,5 actions pour la 4ème souscription des ex-actionnaires et actionnaires actuels comparé au nombre d'actions prises pour leur 3ème souscription

    "))

    Clé de lecture : il y a eu en moyenne une augmentation de 2,5 actions pour la 4ème souscription des ex-actionnaires et actionnaires actuels comparé au nombre d'actions prises pour leur 3ème souscription

    In [ ]:
    Copied!
    import pandas as pd
    import numpy as np
    
    # Fonction pour calculer la proportion de valeurs positives, négatives et stagnantes
    def positive_negative_stagnant_stats(column):
        valid_values = column.dropna()
        
        # Convertir les valeurs en nombres (int ou float)
        numeric_values = pd.to_numeric(valid_values, errors='coerce')
        
        positive_values = numeric_values[numeric_values > 0]
        negative_values = numeric_values[numeric_values < 0]
        stagnant_values = numeric_values[numeric_values == 0]
        
        total_valid = len(valid_values)
        positive_proportion = len(positive_values) / total_valid * 100 if total_valid > 0 else 0
        negative_proportion = len(negative_values) / total_valid * 100 if total_valid > 0 else 0
        stagnant_proportion = len(stagnant_values) / total_valid * 100 if total_valid > 0 else 0
        
        total_proportion = positive_proportion + negative_proportion + stagnant_proportion
        if total_proportion > 0:
            positive_proportion /= total_proportion
            negative_proportion /= total_proportion
            stagnant_proportion /= total_proportion
        
        return pd.Series({
            'Augmentation du nombre d\'actions  par rapport à la précédente': round(positive_proportion, 2),
            'Diminution du nombre d\'actions  par rapport à la précédente': round(negative_proportion, 2),
            'Stagnation  du nombre d\'actions  par rapport à la précédente': round(stagnant_proportion, 2)
        })
    
    # Appliquer la fonction à chaque colonne du DataFrame df_variationactions10
    result_stats = df_variationactions10.apply(positive_negative_stagnant_stats)
    
    result_stats = result_stats.drop(columns= "ID du contact")
    
    import pandas as pd import numpy as np # Fonction pour calculer la proportion de valeurs positives, négatives et stagnantes def positive_negative_stagnant_stats(column): valid_values = column.dropna() # Convertir les valeurs en nombres (int ou float) numeric_values = pd.to_numeric(valid_values, errors='coerce') positive_values = numeric_values[numeric_values > 0] negative_values = numeric_values[numeric_values < 0] stagnant_values = numeric_values[numeric_values == 0] total_valid = len(valid_values) positive_proportion = len(positive_values) / total_valid * 100 if total_valid > 0 else 0 negative_proportion = len(negative_values) / total_valid * 100 if total_valid > 0 else 0 stagnant_proportion = len(stagnant_values) / total_valid * 100 if total_valid > 0 else 0 total_proportion = positive_proportion + negative_proportion + stagnant_proportion if total_proportion > 0: positive_proportion /= total_proportion negative_proportion /= total_proportion stagnant_proportion /= total_proportion return pd.Series({ 'Augmentation du nombre d\'actions par rapport à la précédente': round(positive_proportion, 2), 'Diminution du nombre d\'actions par rapport à la précédente': round(negative_proportion, 2), 'Stagnation du nombre d\'actions par rapport à la précédente': round(stagnant_proportion, 2) }) # Appliquer la fonction à chaque colonne du DataFrame df_variationactions10 result_stats = df_variationactions10.apply(positive_negative_stagnant_stats) result_stats = result_stats.drop(columns= "ID du contact")
    In [ ]:
    Copied!
    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt
    # Transposer le DataFrame pour que les colonnes deviennent des index
    result_stats_transposed = result_stats.transpose()
    
    # Calculer le total des proportions pour chaque souscription
    result_stats_transposed['Total'] = result_stats_transposed.sum(axis=1)
    
    # Convertir les proportions en pourcentages
    result_stats_transposed_percentage = result_stats_transposed.apply(lambda row: row / row['Total'] * 100, axis=1)
    
    # Supprimer la colonne Total
    result_stats_transposed_percentage = result_stats_transposed_percentage.drop(columns='Total')
    
    # Créer un graphique de barres empilées avec les étiquettes de données en pourcentage
    ax = result_stats_transposed_percentage.plot(kind='bar', stacked=True, figsize=(10, 6))
    plt.title('Proportions des catégories variations d\'actions par souscription')
    plt.ylabel('Proportion (%)')
    plt.xlabel('Souscriptions')
    plt.xticks(rotation=45, ha='right')
    
    # Afficher les étiquettes de données en pourcentage sur les parties empilées des barres
    for container in ax.containers:
        for bar in container:
            height = bar.get_height()
            if height > 1:
                ax.annotate(f'{height:.0f} %', (bar.get_x() + bar.get_width() / 2, bar.get_y() + height / 2),
                            ha='center', va='center', color='white', fontsize=8)
            elif height < -1:
                ax.annotate(f'{height:.0f} %', (bar.get_x() + bar.get_width() / 2, bar.get_y() + height / 2),
                            ha='center', va='center', color='black', fontsize=8)
            elif -1 <= height <= 1:
                ax.annotate(f'{height:.1f} %', (bar.get_x() + bar.get_width() / 2, bar.get_y() + height / 2),
                            ha='center', va='center', color='black', fontsize=8)
    
    # Déplacer la légende à droite du graphique
    plt.legend(loc='upper left', bbox_to_anchor=(1, 1))
    
    # Afficher le graphique
    
    plt.show()
    
    import pandas as pd import numpy as np import matplotlib.pyplot as plt # Transposer le DataFrame pour que les colonnes deviennent des index result_stats_transposed = result_stats.transpose() # Calculer le total des proportions pour chaque souscription result_stats_transposed['Total'] = result_stats_transposed.sum(axis=1) # Convertir les proportions en pourcentages result_stats_transposed_percentage = result_stats_transposed.apply(lambda row: row / row['Total'] * 100, axis=1) # Supprimer la colonne Total result_stats_transposed_percentage = result_stats_transposed_percentage.drop(columns='Total') # Créer un graphique de barres empilées avec les étiquettes de données en pourcentage ax = result_stats_transposed_percentage.plot(kind='bar', stacked=True, figsize=(10, 6)) plt.title('Proportions des catégories variations d\'actions par souscription') plt.ylabel('Proportion (%)') plt.xlabel('Souscriptions') plt.xticks(rotation=45, ha='right') # Afficher les étiquettes de données en pourcentage sur les parties empilées des barres for container in ax.containers: for bar in container: height = bar.get_height() if height > 1: ax.annotate(f'{height:.0f} %', (bar.get_x() + bar.get_width() / 2, bar.get_y() + height / 2), ha='center', va='center', color='white', fontsize=8) elif height < -1: ax.annotate(f'{height:.0f} %', (bar.get_x() + bar.get_width() / 2, bar.get_y() + height / 2), ha='center', va='center', color='black', fontsize=8) elif -1 <= height <= 1: ax.annotate(f'{height:.1f} %', (bar.get_x() + bar.get_width() / 2, bar.get_y() + height / 2), ha='center', va='center', color='black', fontsize=8) # Déplacer la légende à droite du graphique plt.legend(loc='upper left', bbox_to_anchor=(1, 1)) # Afficher le graphique plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Nous avons regardé quelle était la part de chaque type de variations du nombre d'actions par rang de différence entre souscriptions</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Nous avons regardé quelle était la part de chaque type de variations du nombre d'actions par rang de différence entre souscriptions

    "))

    Nous avons regardé quelle était la part de chaque type de variations du nombre d'actions par rang de différence entre souscriptions

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Clé de lecture : Parmi les ex-actionnaires et actionnaires actuels, 37 % ont pris plus d'actions pour leur 2ème souscription par rapport à la premiere. 27% en ont pris moins et 36 % ont pris le même nombre d'actions</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Clé de lecture : Parmi les ex-actionnaires et actionnaires actuels, 37 % ont pris plus d'actions pour leur 2ème souscription par rapport à la premiere. 27% en ont pris moins et 36 % ont pris le même nombre d'actions

    "))

    Clé de lecture : Parmi les ex-actionnaires et actionnaires actuels, 37 % ont pris plus d'actions pour leur 2ème souscription par rapport à la premiere. 27% en ont pris moins et 36 % ont pris le même nombre d'actions

    In [ ]:
    Copied!
    import pandas as pd
    import numpy as np
    
    # Fonction pour calculer le nombre absolu de valeurs positives, négatives et stagnantes
    def positive_negative_stagnant_counts(column):
        valid_values = column.dropna()
        
        # Convertir les valeurs en nombres (int ou float)
        numeric_values = pd.to_numeric(valid_values, errors='coerce')
        
        positive_values = numeric_values[numeric_values > 0]
        negative_values = numeric_values[numeric_values < 0]
        stagnant_values = numeric_values[numeric_values == 0]
        
        positive_count = len(positive_values)
        negative_count = len(negative_values)
        stagnant_count = len(stagnant_values)
        
        return pd.Series({
            'Nombre de souscriptions à augmentation d\'actions': positive_count,
            'Nombre de souscriptions à diminution d\'actions': negative_count,
            'Nombre de souscriptions stagnantes': stagnant_count
        })
    
    # Appliquer la fonction à chaque colonne du DataFrame df_variationactions10
    result_counts = df_variationactions10.apply(positive_negative_stagnant_counts)
    
    result_counts = result_counts.drop(columns="ID du contact")
    
    import pandas as pd import numpy as np # Fonction pour calculer le nombre absolu de valeurs positives, négatives et stagnantes def positive_negative_stagnant_counts(column): valid_values = column.dropna() # Convertir les valeurs en nombres (int ou float) numeric_values = pd.to_numeric(valid_values, errors='coerce') positive_values = numeric_values[numeric_values > 0] negative_values = numeric_values[numeric_values < 0] stagnant_values = numeric_values[numeric_values == 0] positive_count = len(positive_values) negative_count = len(negative_values) stagnant_count = len(stagnant_values) return pd.Series({ 'Nombre de souscriptions à augmentation d\'actions': positive_count, 'Nombre de souscriptions à diminution d\'actions': negative_count, 'Nombre de souscriptions stagnantes': stagnant_count }) # Appliquer la fonction à chaque colonne du DataFrame df_variationactions10 result_counts = df_variationactions10.apply(positive_negative_stagnant_counts) result_counts = result_counts.drop(columns="ID du contact")
    In [ ]:
    Copied!
    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt
    
    # Sélectionner les colonnes pour le premier graphique
    selected_columns = [
        'diff_actions_souscriptions_2_1',
        'diff_actions_souscriptions_3_2',
        'diff_actions_souscriptions_4_3',
        'diff_actions_souscriptions_5_4'
    ]
    
    # Transposer le DataFrame pour que les colonnes deviennent des index
    result_counts_selected = result_counts[selected_columns].transpose()
    
    # Créer un graphique de barres empilées avec les étiquettes de données en nombre absolu (premier graphique)
    ax1 = result_counts_selected.plot(kind='bar', stacked=True, figsize=(10, 6))
    plt.title('Nombre de personnes par catégories de variations du nombre d\'actions d\'une souscription à une autre (jusqu\'à la 5 souscriptions)')
    plt.ylabel('Nombre absolu')
    plt.xlabel('Souscriptions')
    plt.xticks(rotation=45, ha='right')
    
    # Afficher les étiquettes de données en nombre absolu sur les parties empilées des barres
    for container in ax1.containers:
        for bar in container:
            height = bar.get_height()
            ax1.annotate(f'{int(height)}', (bar.get_x() + bar.get_width() / 2, bar.get_y() + height / 2),
                         ha='center', va='center', color='black', fontsize=8)
    
    # Déplacer la légende à droite du graphique
    plt.legend(loc='upper left', bbox_to_anchor=(1, 1))
    
    # Afficher le premier graphique
    plt.show()
    
    import pandas as pd import numpy as np import matplotlib.pyplot as plt # Sélectionner les colonnes pour le premier graphique selected_columns = [ 'diff_actions_souscriptions_2_1', 'diff_actions_souscriptions_3_2', 'diff_actions_souscriptions_4_3', 'diff_actions_souscriptions_5_4' ] # Transposer le DataFrame pour que les colonnes deviennent des index result_counts_selected = result_counts[selected_columns].transpose() # Créer un graphique de barres empilées avec les étiquettes de données en nombre absolu (premier graphique) ax1 = result_counts_selected.plot(kind='bar', stacked=True, figsize=(10, 6)) plt.title('Nombre de personnes par catégories de variations du nombre d\'actions d\'une souscription à une autre (jusqu\'à la 5 souscriptions)') plt.ylabel('Nombre absolu') plt.xlabel('Souscriptions') plt.xticks(rotation=45, ha='right') # Afficher les étiquettes de données en nombre absolu sur les parties empilées des barres for container in ax1.containers: for bar in container: height = bar.get_height() ax1.annotate(f'{int(height)}', (bar.get_x() + bar.get_width() / 2, bar.get_y() + height / 2), ha='center', va='center', color='black', fontsize=8) # Déplacer la légende à droite du graphique plt.legend(loc='upper left', bbox_to_anchor=(1, 1)) # Afficher le premier graphique plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Clé de lecture : Parmi les ex-actionnaires et actionnaires actuels, il y avait 2183 personnes qui ont pris plus d'actions pour leur deuxième souscription par rapport à la première</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Clé de lecture : Parmi les ex-actionnaires et actionnaires actuels, il y avait 2183 personnes qui ont pris plus d'actions pour leur deuxième souscription par rapport à la première

    "))

    Clé de lecture : Parmi les ex-actionnaires et actionnaires actuels, il y avait 2183 personnes qui ont pris plus d'actions pour leur deuxième souscription par rapport à la première

    In [ ]:
    Copied!
    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt
    
    # Sélectionner les colonnes pour le deuxième graphique (en excluant les colonnes du premier graphique)
    selected_columns = [
        'diff_actions_souscriptions_6_5',
        'diff_actions_souscriptions_7_6',
        'diff_actions_souscriptions_8_7',
        'diff_actions_souscriptions_9_8',
        'diff_actions_souscriptions_10_9'
    ]
    
    # Transposer le DataFrame pour que les colonnes deviennent des index
    result_counts_selected = result_counts[selected_columns].transpose()
    
    # Créer un graphique de barres empilées avec les étiquettes de données en nombre absolu (deuxième graphique)
    ax2 = result_counts_selected.plot(kind='bar', stacked=True, figsize=(10, 6))
    plt.title('Nombre de personnes par catégories de variations du nombre d\'actions d\'une souscription à une autre (jusqu\'à la 10 souscriptions)')
    plt.ylabel('Nombre absolu')
    plt.xlabel('Souscriptions')
    plt.xticks(rotation=45, ha='right')
    
    # Afficher les étiquettes de données en nombre absolu sur les parties empilées des barres
    for container in ax2.containers:
        for bar in container:
            height = bar.get_height()
            ax2.annotate(f'{int(height)}', (bar.get_x() + bar.get_width() / 2, bar.get_y() + height / 2),
                         ha='center', va='center', color='black', fontsize=8)
    
    # Déplacer la légende à droite du graphique
    plt.legend(loc='upper left', bbox_to_anchor=(1, 1))
    
    # Afficher le deuxième graphique
    plt.show()
    
    import pandas as pd import numpy as np import matplotlib.pyplot as plt # Sélectionner les colonnes pour le deuxième graphique (en excluant les colonnes du premier graphique) selected_columns = [ 'diff_actions_souscriptions_6_5', 'diff_actions_souscriptions_7_6', 'diff_actions_souscriptions_8_7', 'diff_actions_souscriptions_9_8', 'diff_actions_souscriptions_10_9' ] # Transposer le DataFrame pour que les colonnes deviennent des index result_counts_selected = result_counts[selected_columns].transpose() # Créer un graphique de barres empilées avec les étiquettes de données en nombre absolu (deuxième graphique) ax2 = result_counts_selected.plot(kind='bar', stacked=True, figsize=(10, 6)) plt.title('Nombre de personnes par catégories de variations du nombre d\'actions d\'une souscription à une autre (jusqu\'à la 10 souscriptions)') plt.ylabel('Nombre absolu') plt.xlabel('Souscriptions') plt.xticks(rotation=45, ha='right') # Afficher les étiquettes de données en nombre absolu sur les parties empilées des barres for container in ax2.containers: for bar in container: height = bar.get_height() ax2.annotate(f'{int(height)}', (bar.get_x() + bar.get_width() / 2, bar.get_y() + height / 2), ha='center', va='center', color='black', fontsize=8) # Déplacer la légende à droite du graphique plt.legend(loc='upper left', bbox_to_anchor=(1, 1)) # Afficher le deuxième graphique plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    # Liste des colonnes de variation
    df_variationactions10groupe = df_variationactions10.copy()
    variation_columns = [col for col in df_variationactions10.columns if col.startswith("diff_actions_souscriptions_")]
    
    # Fonction pour déterminer la catégorie de variation
    def determine_variation_category(value):
        if value < 0:
            return "Diminution"
        elif value > 0:
            return "Augmentation"
        else:
            return "Stagnation"
    
    # Ajouter les colonnes "catégorie de variations" pour chaque colonne de variation
    for col in variation_columns:
        new_col_name = col.replace("diff_actions_", "catégorie de variations ")
        df_variationactions10groupe[new_col_name] = df_variationactions10groupe[col].apply(determine_variation_category)
    
    # Liste des colonnes de variation df_variationactions10groupe = df_variationactions10.copy() variation_columns = [col for col in df_variationactions10.columns if col.startswith("diff_actions_souscriptions_")] # Fonction pour déterminer la catégorie de variation def determine_variation_category(value): if value < 0: return "Diminution" elif value > 0: return "Augmentation" else: return "Stagnation" # Ajouter les colonnes "catégorie de variations" pour chaque colonne de variation for col in variation_columns: new_col_name = col.replace("diff_actions_", "catégorie de variations ") df_variationactions10groupe[new_col_name] = df_variationactions10groupe[col].apply(determine_variation_category)
    In [ ]:
    Copied!
    import pandas as pd
    from IPython.display import display
    
    
    # Liste des colonnes de variation et de catégorie de variation
    variation_columns = [
        'diff_actions_souscriptions_2_1', 'diff_actions_souscriptions_3_2', 'diff_actions_souscriptions_4_3',
        'diff_actions_souscriptions_5_4', 'diff_actions_souscriptions_6_5', 'diff_actions_souscriptions_7_6',
        'diff_actions_souscriptions_8_7', 'diff_actions_souscriptions_9_8', 'diff_actions_souscriptions_10_9'
    ]
    category_columns = [
        'catégorie de variations souscriptions_2_1', 'catégorie de variations souscriptions_3_2',
        'catégorie de variations souscriptions_4_3', 'catégorie de variations souscriptions_5_4',
        'catégorie de variations souscriptions_6_5', 'catégorie de variations souscriptions_7_6',
        'catégorie de variations souscriptions_8_7', 'catégorie de variations souscriptions_9_8',
        'catégorie de variations souscriptions_10_9'
    ]
    
    # Créer les 9 tableaux de avec les valeurs de variations et leur catégories de variations pour chaque écart entre souscriptions
    tableaux = []
    for variation_col, category_col in zip(variation_columns, category_columns):
        tableau = df_variationactions10groupe[[variation_col, category_col]].copy()
        col_name = f"variation_{variation_col.split('_')[3]}_{variation_col.split('_')[4]}"
        cat_col_name = f"catégorie_{category_col.split('_')[-2]}_{category_col.split('_')[-1]}"
        tableau.columns = [col_name, cat_col_name]
        tableau = tableau.dropna().loc[tableau[cat_col_name] != 'Stagnation']
        tableaux.append(tableau)
    
    # créer des tableau pour calculer la moyenne des colonnes 'variation_{i}_{i-1}' groupée par 'Catégorie'
    mean_data = []
    for i, tableau in enumerate(tableaux, start=2):
        mean_value = tableau.groupby(f'catégorie_{i}_{i-1}')[f'variation_{i}_{i-1}'].mean().reset_index()
        mean_data.append(mean_value)
        
    # Fusionner les données sur la clé 'Catégorie'
    merged_mean_data = pd.concat(mean_data, axis=1)
    
    # Afficher le DataFrame résultant
    merged_mean_data
    # Supprimer les colonnes 'catégorie_{i}_{i-1}' à partir de 'catégorie_3_2'
    cols_to_drop = ['catégorie_3_2', 'catégorie_4_3', 'catégorie_5_4', 'catégorie_6_5', 'catégorie_7_6',
                    'catégorie_8_7', 'catégorie_9_8', 'catégorie_10_9']
    merged_mean_data.drop(columns=cols_to_drop, inplace=True)
    
    merged_mean_data.rename(columns={'catégorie_2_1': 'Catégorie de Variation'}, inplace=True)
    merged_mean_data = merged_mean_data.round()
    
    import pandas as pd from IPython.display import display # Liste des colonnes de variation et de catégorie de variation variation_columns = [ 'diff_actions_souscriptions_2_1', 'diff_actions_souscriptions_3_2', 'diff_actions_souscriptions_4_3', 'diff_actions_souscriptions_5_4', 'diff_actions_souscriptions_6_5', 'diff_actions_souscriptions_7_6', 'diff_actions_souscriptions_8_7', 'diff_actions_souscriptions_9_8', 'diff_actions_souscriptions_10_9' ] category_columns = [ 'catégorie de variations souscriptions_2_1', 'catégorie de variations souscriptions_3_2', 'catégorie de variations souscriptions_4_3', 'catégorie de variations souscriptions_5_4', 'catégorie de variations souscriptions_6_5', 'catégorie de variations souscriptions_7_6', 'catégorie de variations souscriptions_8_7', 'catégorie de variations souscriptions_9_8', 'catégorie de variations souscriptions_10_9' ] # Créer les 9 tableaux de avec les valeurs de variations et leur catégories de variations pour chaque écart entre souscriptions tableaux = [] for variation_col, category_col in zip(variation_columns, category_columns): tableau = df_variationactions10groupe[[variation_col, category_col]].copy() col_name = f"variation_{variation_col.split('_')[3]}_{variation_col.split('_')[4]}" cat_col_name = f"catégorie_{category_col.split('_')[-2]}_{category_col.split('_')[-1]}" tableau.columns = [col_name, cat_col_name] tableau = tableau.dropna().loc[tableau[cat_col_name] != 'Stagnation'] tableaux.append(tableau) # créer des tableau pour calculer la moyenne des colonnes 'variation_{i}_{i-1}' groupée par 'Catégorie' mean_data = [] for i, tableau in enumerate(tableaux, start=2): mean_value = tableau.groupby(f'catégorie_{i}_{i-1}')[f'variation_{i}_{i-1}'].mean().reset_index() mean_data.append(mean_value) # Fusionner les données sur la clé 'Catégorie' merged_mean_data = pd.concat(mean_data, axis=1) # Afficher le DataFrame résultant merged_mean_data # Supprimer les colonnes 'catégorie_{i}_{i-1}' à partir de 'catégorie_3_2' cols_to_drop = ['catégorie_3_2', 'catégorie_4_3', 'catégorie_5_4', 'catégorie_6_5', 'catégorie_7_6', 'catégorie_8_7', 'catégorie_9_8', 'catégorie_10_9'] merged_mean_data.drop(columns=cols_to_drop, inplace=True) merged_mean_data.rename(columns={'catégorie_2_1': 'Catégorie de Variation'}, inplace=True) merged_mean_data = merged_mean_data.round()
    In [ ]:
    Copied!
    import matplotlib.pyplot as plt
    
    # Données pour le tracé
    categories = merged_mean_data['Catégorie de Variation']
    variations_augmentation = merged_mean_data.loc[merged_mean_data['Catégorie de Variation'] == 'Augmentation'].iloc[:, 1:]
    variations_diminution = merged_mean_data.loc[merged_mean_data['Catégorie de Variation'] == 'Diminution'].iloc[:, 1:]
    
    # Tracer les courbes
    plt.figure(figsize=(10, 6))
    
    for category, data in [('Augmentation', variations_augmentation), ('Diminution', variations_diminution)]:
        plt.plot(data.columns, data.iloc[0], marker='o', label=category)
    
    plt.title('Moyenne des variations en fonction de la catégorie de variation d\'actions d\'une souscription à une autre')
    plt.xlabel('Variation')
    plt.ylabel('Moyenne')
    plt.legend()
    plt.grid(True)
    plt.xticks(rotation=45)
    plt.yticks(range(-150, 150, 20))  # Ajuster les graduations de l'axe des y
    plt.tight_layout()
    
    # Annoter les points avec les valeurs
    for category, data in [('Augmentation', variations_augmentation), ('Diminution', variations_diminution)]:
        for i, value in enumerate(data.iloc[0]):
            plt.annotate(f'{value:.0f}', (data.columns[i], value), textcoords="offset points", xytext=(0,10), ha='center', fontsize=9, fontweight='normal')
    
    # Afficher le graphique
    plt.show()
    
    import matplotlib.pyplot as plt # Données pour le tracé categories = merged_mean_data['Catégorie de Variation'] variations_augmentation = merged_mean_data.loc[merged_mean_data['Catégorie de Variation'] == 'Augmentation'].iloc[:, 1:] variations_diminution = merged_mean_data.loc[merged_mean_data['Catégorie de Variation'] == 'Diminution'].iloc[:, 1:] # Tracer les courbes plt.figure(figsize=(10, 6)) for category, data in [('Augmentation', variations_augmentation), ('Diminution', variations_diminution)]: plt.plot(data.columns, data.iloc[0], marker='o', label=category) plt.title('Moyenne des variations en fonction de la catégorie de variation d\'actions d\'une souscription à une autre') plt.xlabel('Variation') plt.ylabel('Moyenne') plt.legend() plt.grid(True) plt.xticks(rotation=45) plt.yticks(range(-150, 150, 20)) # Ajuster les graduations de l'axe des y plt.tight_layout() # Annoter les points avec les valeurs for category, data in [('Augmentation', variations_augmentation), ('Diminution', variations_diminution)]: for i, value in enumerate(data.iloc[0]): plt.annotate(f'{value:.0f}', (data.columns[i], value), textcoords="offset points", xytext=(0,10), ha='center', fontsize=9, fontweight='normal') # Afficher le graphique plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Tableau de données pour le graphique précédent</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Tableau de données pour le graphique précédent

    "))

    Tableau de données pour le graphique précédent

    In [ ]:
    Copied!
    merged_mean_data
    
    merged_mean_data
    Out[ ]:
    Catégorie de Variation variation_2_1 variation_3_2 variation_4_3 variation_5_4 variation_6_5 variation_7_6 variation_8_7 variation_9_8 variation_10_9
    0 Augmentation 78.0 70.0 75.0 73.0 71.0 51.0 88.0 84.0 112.0
    1 Diminution -77.0 -81.0 -72.0 -73.0 -48.0 -75.0 -65.0 -63.0 -47.0
    In [ ]:
    Copied!
     from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Clé de lecture : Parmis les ex-actionnaires et actionnaires actuels qui ont pris plus d'actions pour leur 2ème souscription par rapport à la premiere, en moyenne ces derniers en ont pris 34 de plus. Et parmi ceux qui ont diminué leur nombre d'actions pour leur 2ème souscriptons par rapport à la première, ils en ont pris en moyenne 34 de moins</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Clé de lecture : Parmis les ex-actionnaires et actionnaires actuels qui ont pris plus d'actions pour leur 2ème souscription par rapport à la premiere, en moyenne ces derniers en ont pris 34 de plus. Et parmi ceux qui ont diminué leur nombre d'actions pour leur 2ème souscriptons par rapport à la première, ils en ont pris en moyenne 34 de moins

    "))

    Clé de lecture : Parmis les ex-actionnaires et actionnaires actuels qui ont pris plus d'actions pour leur 2ème souscription par rapport à la premiere, en moyenne ces derniers en ont pris 34 de plus. Et parmi ceux qui ont diminué leur nombre d'actions pour leur 2ème souscriptons par rapport à la première, ils en ont pris en moyenne 34 de moins

    In [ ]:
    Copied!
    from IPython.display import display, HTML
    
    
    # Insérer un saut de page
    display(HTML("<div style='page-break-before: always;'></div>"))
    
    # Afficher un titre centré avec une taille de police plus grande
    display(HTML('<center><h2><u>Variations relatives du nombre d\'actions entre rang de souscriptions</u></h2></center>'))
    
    from IPython.display import display, HTML # Insérer un saut de page display(HTML("
    ")) # Afficher un titre centré avec une taille de police plus grande display(HTML('

    Variations relatives du nombre d\'actions entre rang de souscriptions

    '))

    Variations relatives du nombre d'actions entre rang de souscriptions

    In [ ]:
    Copied!
    from IPython.display import display, HTML
    
    # Afficher un titre centré avec une taille de police plus grande
    display(HTML('<h3>Notions : Nous avons pour cette section considérer les logarithmes néperiens (base e) du nombres d\'actions échangées à chaque rangs de souscriptions. Ainsi en faisant la soustraction entre entre 2 log on peut avoir une idée de la variation absolue entre le nombre d\'actions. Dans la section précédente on observait qu\'en moyenne entre la 2ème et la 1ere souscription les actionnaires prennaient 4 actions de plus que la fois précédente, ce qui n\'indique rien sur l\'évolution relative sur son comportement de souscription. La personne aurait avoir pris lors de la 1ere souscription 4 actions et lors de la 2eme 8 actions ce qui fait une augmentation de 100 % soit 2 fois plus une fois sur l\'autre. L\'actionnaire aurait pu avoir pris 400 actions lors de la 1ere souscription et 404 lors de la 2ème souscrition soit une augmentation de 1% ou 1,01 fois plus une fois sur l\'autre. Avec le logarithme népérien on peut avoir une idée de l\évolution relative en faisant e^(log(x en T+1) - log(X en T)) = e^(log(x en T+1/(X en T)). Ainsi pour reprendre nos exemples e^(log(8)-log(4)) = e^log(8/4) = 2 et  e^(log(404)-log(400)) = e^log(404/400) = 1,01 </h3>'))
    
    from IPython.display import display, HTML # Afficher un titre centré avec une taille de police plus grande display(HTML('

    Notions : Nous avons pour cette section considérer les logarithmes néperiens (base e) du nombres d\'actions échangées à chaque rangs de souscriptions. Ainsi en faisant la soustraction entre entre 2 log on peut avoir une idée de la variation absolue entre le nombre d\'actions. Dans la section précédente on observait qu\'en moyenne entre la 2ème et la 1ere souscription les actionnaires prennaient 4 actions de plus que la fois précédente, ce qui n\'indique rien sur l\'évolution relative sur son comportement de souscription. La personne aurait avoir pris lors de la 1ere souscription 4 actions et lors de la 2eme 8 actions ce qui fait une augmentation de 100 % soit 2 fois plus une fois sur l\'autre. L\'actionnaire aurait pu avoir pris 400 actions lors de la 1ere souscription et 404 lors de la 2ème souscrition soit une augmentation de 1% ou 1,01 fois plus une fois sur l\'autre. Avec le logarithme népérien on peut avoir une idée de l\évolution relative en faisant e^(log(x en T+1) - log(X en T)) = e^(log(x en T+1/(X en T)). Ainsi pour reprendre nos exemples e^(log(8)-log(4)) = e^log(8/4) = 2 et e^(log(404)-log(400)) = e^log(404/400) = 1,01

    '))

    Notions : Nous avons pour cette section considérer les logarithmes néperiens (base e) du nombres d'actions échangées à chaque rangs de souscriptions. Ainsi en faisant la soustraction entre entre 2 log on peut avoir une idée de la variation absolue entre le nombre d'actions. Dans la section précédente on observait qu'en moyenne entre la 2ème et la 1ere souscription les actionnaires prennaient 4 actions de plus que la fois précédente, ce qui n'indique rien sur l'évolution relative sur son comportement de souscription. La personne aurait avoir pris lors de la 1ere souscription 4 actions et lors de la 2eme 8 actions ce qui fait une augmentation de 100 % soit 2 fois plus une fois sur l'autre. L'actionnaire aurait pu avoir pris 400 actions lors de la 1ere souscription et 404 lors de la 2ème souscrition soit une augmentation de 1% ou 1,01 fois plus une fois sur l'autre. Avec le logarithme népérien on peut avoir une idée de l\évolution relative en faisant e^(log(x en T+1) - log(X en T)) = e^(log(x en T+1/(X en T)). Ainsi pour reprendre nos exemples e^(log(8)-log(4)) = e^log(8/4) = 2 et e^(log(404)-log(400)) = e^log(404/400) = 1,01

    In [ ]:
    Copied!
    df_log = np.log(df_log)
    #renommer les colonnes
    df_log.columns = [f'{col[0]}_{col[1]}' for col in df_log.columns]
    df_log.reset_index(inplace=True)
    # Créer les colonnes de différences de nombres d'actions
    for i in range(2, 11):
        df_log[f'Log_diff_actions_souscriptions_{i}_{i-1}'] = df_log[f'Nombre d\'actions échangées_{i}'] - df_log[f'Nombre d\'actions échangées_{i-1}']
    
    # Supprimer les colonnes du tableau
    
    colonnes_a_supprimer = [
       "Nombre d'actions échangées_1",
    "Nombre d'actions échangées_2",
    "Nombre d'actions échangées_3",
    "Nombre d'actions échangées_4",
    "Nombre d'actions échangées_5",
    "Nombre d'actions échangées_6",
    "Nombre d'actions échangées_7",
    "Nombre d'actions échangées_8",
    "Nombre d'actions échangées_9",
    "Nombre d'actions échangées_10"
    ]
    
    # calculer les variations moyenne par colonnes 
    df_log.drop(colonnes_a_supprimer, axis=1, inplace=True)
    Variation_actionslog = df_log.drop(columns='ID du contact').mean(skipna=True).to_frame()
    import matplotlib.pyplot as plt
    
    # Données pour l'axe x (colonnes)
    colonnes = Variation_actionslog.index
    
    # Données pour l'axe y (moyennes)
    moyennes_values = Variation_actionslog.values
    
    # Créer le graphique
    plt.figure(figsize=(10, 6))
    plt.plot(colonnes, moyennes_values, marker='o', linestyle='-', color='darkblue')
    plt.axhline(y=0, color='red', linestyle='--', linewidth=1)  # Ligne du 0 en rouge
    plt.xlabel('Rang de souscription')
    plt.ylabel('Moyenne des différence des logs')
    plt.title('Variations moyennes totale du nombre d\'actions entre souscriptions (jusqu\'à 10)(log-différence)')
    plt.xticks(rotation=60)
    plt.grid(True)
    
    
    
    # Afficher le graphique
    plt.tight_layout()
    plt.show()
    
    df_log = np.log(df_log) #renommer les colonnes df_log.columns = [f'{col[0]}_{col[1]}' for col in df_log.columns] df_log.reset_index(inplace=True) # Créer les colonnes de différences de nombres d'actions for i in range(2, 11): df_log[f'Log_diff_actions_souscriptions_{i}_{i-1}'] = df_log[f'Nombre d\'actions échangées_{i}'] - df_log[f'Nombre d\'actions échangées_{i-1}'] # Supprimer les colonnes du tableau colonnes_a_supprimer = [ "Nombre d'actions échangées_1", "Nombre d'actions échangées_2", "Nombre d'actions échangées_3", "Nombre d'actions échangées_4", "Nombre d'actions échangées_5", "Nombre d'actions échangées_6", "Nombre d'actions échangées_7", "Nombre d'actions échangées_8", "Nombre d'actions échangées_9", "Nombre d'actions échangées_10" ] # calculer les variations moyenne par colonnes df_log.drop(colonnes_a_supprimer, axis=1, inplace=True) Variation_actionslog = df_log.drop(columns='ID du contact').mean(skipna=True).to_frame() import matplotlib.pyplot as plt # Données pour l'axe x (colonnes) colonnes = Variation_actionslog.index # Données pour l'axe y (moyennes) moyennes_values = Variation_actionslog.values # Créer le graphique plt.figure(figsize=(10, 6)) plt.plot(colonnes, moyennes_values, marker='o', linestyle='-', color='darkblue') plt.axhline(y=0, color='red', linestyle='--', linewidth=1) # Ligne du 0 en rouge plt.xlabel('Rang de souscription') plt.ylabel('Moyenne des différence des logs') plt.title('Variations moyennes totale du nombre d\'actions entre souscriptions (jusqu\'à 10)(log-différence)') plt.xticks(rotation=60) plt.grid(True) # Afficher le graphique plt.tight_layout() plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    #Variation_actionslog = Variation_actionslog.T
    Variation_actionslog = Variation_actionslog.rename(columns={Variation_actionslog.columns[0]: 'log(i+1) - log(i)'})
    Variation_actionslog['e^log(x)'] = np.exp(Variation_actionslog.iloc[:, 0])
    Variation_actionslog 
    
    #Variation_actionslog = Variation_actionslog.T Variation_actionslog = Variation_actionslog.rename(columns={Variation_actionslog.columns[0]: 'log(i+1) - log(i)'}) Variation_actionslog['e^log(x)'] = np.exp(Variation_actionslog.iloc[:, 0]) Variation_actionslog
    Out[ ]:
    log(i+1) - log(i) e^log(x)
    Log_diff_actions_souscriptions_2_1 -0.026232 0.974109
    Log_diff_actions_souscriptions_3_2 0.041931 1.042823
    Log_diff_actions_souscriptions_4_3 -0.025583 0.974742
    Log_diff_actions_souscriptions_5_4 0.001804 1.001806
    Log_diff_actions_souscriptions_6_5 -0.114651 0.891677
    Log_diff_actions_souscriptions_7_6 0.078376 1.081529
    Log_diff_actions_souscriptions_8_7 0.100767 1.106019
    Log_diff_actions_souscriptions_9_8 0.248553 1.282169
    Log_diff_actions_souscriptions_10_9 0.362496 1.436911
    In [ ]:
    Copied!
    from IPython.display import display, HTML
    
    # Afficher un titre centré avec une taille de police plus grande
    display(HTML('<h4> Clé de lecture : Dans la colonne de droite on peut se rendre compte en moyenne combien de fois plus ou moins les actionnaires ont pris d\'actions d\'une souscription à une autre. Si le nombre est supérieur à 1 il s\'agira d\'une augmentation et s\'il es inférieur, il s\'agira d\'une diminution.</h3>'))
    
    from IPython.display import display, HTML # Afficher un titre centré avec une taille de police plus grande display(HTML('

    Clé de lecture : Dans la colonne de droite on peut se rendre compte en moyenne combien de fois plus ou moins les actionnaires ont pris d\'actions d\'une souscription à une autre. Si le nombre est supérieur à 1 il s\'agira d\'une augmentation et s\'il es inférieur, il s\'agira d\'une diminution.'))

    Clé de lecture : Dans la colonne de droite on peut se rendre compte en moyenne combien de fois plus ou moins les actionnaires ont pris d'actions d'une souscription à une autre. Si le nombre est supérieur à 1 il s'agira d'une augmentation et s'il es inférieur, il s'agira d'une diminution.

    In [ ]:
    Copied!
    df_log = df_log.merge(df_parcours, on=['ID du contact'], how='left')
    df_log21 = df_log[["Log_diff_actions_souscriptions_2_1", "Nombre moyen d'actions par souscription"]]
    df_log32 = df_log[["Log_diff_actions_souscriptions_3_2", "Nombre moyen d'actions par souscription"]]
    df_log43 = df_log[["Log_diff_actions_souscriptions_4_3", "Nombre moyen d'actions par souscription"]]
    df_log54 = df_log[["Log_diff_actions_souscriptions_5_4", "Nombre moyen d'actions par souscription"]]
    df_log65 = df_log[["Log_diff_actions_souscriptions_6_5", "Nombre moyen d'actions par souscription"]]
    df_log76 = df_log[["Log_diff_actions_souscriptions_7_6", "Nombre moyen d'actions par souscription"]]
    df_log87 = df_log[["Log_diff_actions_souscriptions_8_7", "Nombre moyen d'actions par souscription"]]
    df_log98 = df_log[["Log_diff_actions_souscriptions_9_8", "Nombre moyen d'actions par souscription"]]
    df_log109 = df_log[["Log_diff_actions_souscriptions_10_9", "Nombre moyen d'actions par souscription"]]
    import numpy as np
    
    # Créer une fonction pour attribuer des catégories en fonction de la valeur
    def categorize_variation(val):
        if val == 0:
            return '[0]'
        elif -0.2 < val < 0:
            return ']-0,2;0['
        elif -0.4 < val <= -0.2:
            return ']-0.4;-0.2]'
        elif -0.8 < val <= -0.4:
            return ']-0.8;-0.4]'
        elif -1.6 < val <= -0.8:
            return ']-1.6;-0.8]'
        elif -3.2 < val <= -1.6:
            return ']-3.2;-1.6]'
        elif val < -3.2:
            return '<-3.2'
        elif 0 < val <= 0.2:
            return ']0;0.2]'
        elif 0.2 < val <= 0.4:
            return ']0.2;0.4]'
        elif 0.4 < val <= 0.8:
            return ']0.4;0.8]'
        elif 0.8 < val <= 1.6:
            return ']0.8;1.6]'
        elif 1.6 < val <= 3.2:
            return ']1.6;3.2]'
        elif val > 3.2:
            return '>3.2'
    
    df_log21['Catégorie variation'] = df_log21['Log_diff_actions_souscriptions_2_1'].apply(categorize_variation)
    df_log32['Catégorie variation'] = df_log32['Log_diff_actions_souscriptions_3_2'].apply(categorize_variation)
    df_log43['Catégorie variation'] = df_log43['Log_diff_actions_souscriptions_4_3'].apply(categorize_variation)
    df_log54['Catégorie variation'] = df_log54['Log_diff_actions_souscriptions_5_4'].apply(categorize_variation)
    df_log65['Catégorie variation'] = df_log65['Log_diff_actions_souscriptions_6_5'].apply(categorize_variation)
    df_log76['Catégorie variation'] = df_log76['Log_diff_actions_souscriptions_7_6'].apply(categorize_variation)
    df_log87['Catégorie variation'] = df_log87['Log_diff_actions_souscriptions_8_7'].apply(categorize_variation)
    df_log98['Catégorie variation'] = df_log98['Log_diff_actions_souscriptions_9_8'].apply(categorize_variation)
    df_log109['Catégorie variation'] = df_log109['Log_diff_actions_souscriptions_10_9'].apply(categorize_variation)
    
    def categorize_actions(val):
        if val <= 3:
            return ']0;3]'
        elif val <= 6:
            return ']3;6]'
        elif val <= 18:
            return ']6;18]'
        elif val <= 54:
            return ']18;54]'
        elif val <= 162:
            return ']54;162]'
        else:
            return '>162'
    
    
    df_log21['Catégorie Nombre moyen d\'actions par souscription'] = df_log21['Nombre moyen d\'actions par souscription'].apply(categorize_actions)
    df_log32['Catégorie Nombre moyen d\'actions par souscription'] = df_log32['Nombre moyen d\'actions par souscription'].apply(categorize_actions)
    df_log43['Catégorie Nombre moyen d\'actions par souscription'] = df_log43['Nombre moyen d\'actions par souscription'].apply(categorize_actions)
    df_log54['Catégorie Nombre moyen d\'actions par souscription'] = df_log54['Nombre moyen d\'actions par souscription'].apply(categorize_actions)
    df_log65['Catégorie Nombre moyen d\'actions par souscription'] = df_log65['Nombre moyen d\'actions par souscription'].apply(categorize_actions)
    df_log76['Catégorie Nombre moyen d\'actions par souscription'] = df_log76['Nombre moyen d\'actions par souscription'].apply(categorize_actions)
    df_log87['Catégorie Nombre moyen d\'actions par souscription'] = df_log87['Nombre moyen d\'actions par souscription'].apply(categorize_actions)
    df_log98['Catégorie Nombre moyen d\'actions par souscription'] = df_log98['Nombre moyen d\'actions par souscription'].apply(categorize_actions)
    df_log109['Catégorie Nombre moyen d\'actions par souscription'] = df_log109['Nombre moyen d\'actions par souscription'].apply(categorize_actions)
    cross_tab21 = pd.crosstab(df_log21['Catégorie variation'], df_log21['Catégorie Nombre moyen d\'actions par souscription'])
    cross_tab32 = pd.crosstab(df_log32['Catégorie variation'], df_log32['Catégorie Nombre moyen d\'actions par souscription'])
    cross_tab43 = pd.crosstab(df_log43['Catégorie variation'], df_log43['Catégorie Nombre moyen d\'actions par souscription'])
    cross_tab54 = pd.crosstab(df_log54['Catégorie variation'], df_log54['Catégorie Nombre moyen d\'actions par souscription'])
    cross_tab65 = pd.crosstab(df_log65['Catégorie variation'], df_log65['Catégorie Nombre moyen d\'actions par souscription'])
    cross_tab76 = pd.crosstab(df_log76['Catégorie variation'], df_log76['Catégorie Nombre moyen d\'actions par souscription'])
    cross_tab87 = pd.crosstab(df_log87['Catégorie variation'], df_log87['Catégorie Nombre moyen d\'actions par souscription'])
    cross_tab98 = pd.crosstab(df_log98['Catégorie variation'], df_log98['Catégorie Nombre moyen d\'actions par souscription'])
    cross_tab109 = pd.crosstab(df_log109['Catégorie variation'], df_log109['Catégorie Nombre moyen d\'actions par souscription'])
    cross_tab21 = cross_tab21.reindex(['<-3.2', ']-3.2;-1.6]', ']-1.6;-0.8]', ']-0.8;-0.4]', ']-0.4;-0.2]',']-0,2;0[', '[0]', ']0;0.2]', ']0.2;0.4]', ']0.4;0.8]', ']0.8;1.6]', ']1.6;3.2]', '>3.2'])
    cross_tab32 = cross_tab32.reindex(['<-3.2', ']-3.2;-1.6]', ']-1.6;-0.8]', ']-0.8;-0.4]', ']-0.4;-0.2]',']-0,2;0[', '[0]', ']0;0.2]', ']0.2;0.4]', ']0.4;0.8]', ']0.8;1.6]', ']1.6;3.2]', '>3.2'])
    cross_tab54 = cross_tab54.reindex(['<-3.2', ']-3.2;-1.6]', ']-1.6;-0.8]', ']-0.8;-0.4]', ']-0.4;-0.2]',']-0,2;0[', '[0]', ']0;0.2]', ']0.2;0.4]', ']0.4;0.8]', ']0.8;1.6]', ']1.6;3.2]', '>3.2'])
    cross_tab65 = cross_tab65.reindex(['<-3.2', ']-3.2;-1.6]', ']-1.6;-0.8]', ']-0.8;-0.4]', ']-0.4;-0.2]',']-0,2;0[', '[0]', ']0;0.2]', ']0.2;0.4]', ']0.4;0.8]', ']0.8;1.6]', ']1.6;3.2]', '>3.2'])
    cross_tab76 = cross_tab76.reindex(['<-3.2', ']-3.2;-1.6]', ']-1.6;-0.8]', ']-0.8;-0.4]', ']-0.4;-0.2]',']-0,2;0[', '[0]', ']0;0.2]', ']0.2;0.4]', ']0.4;0.8]', ']0.8;1.6]', ']1.6;3.2]', '>3.2'])
    cross_tab87 = cross_tab87.reindex(['<-3.2', ']-3.2;-1.6]', ']-1.6;-0.8]', ']-0.8;-0.4]', ']-0.4;-0.2]',']-0,2;0[', '[0]', ']0;0.2]', ']0.2;0.4]', ']0.4;0.8]', ']0.8;1.6]', ']1.6;3.2]', '>3.2'])
    cross_tab98 = cross_tab98.reindex(['<-3.2', ']-3.2;-1.6]', ']-1.6;-0.8]', ']-0.8;-0.4]', ']-0.4;-0.2]',']-0,2;0[', '[0]', ']0;0.2]', ']0.2;0.4]', ']0.4;0.8]', ']0.8;1.6]', ']1.6;3.2]', '>3.2'])
    cross_tab109 = cross_tab109.reindex(['<-3.2', ']-3.2;-1.6]', ']-1.6;-0.8]', ']-0.8;-0.4]', ']-0.4;-0.2]',']-0,2;0[', '[0]', ']0;0.2]', ']0.2;0.4]', ']0.4;0.8]', ']0.8;1.6]', ']1.6;3.2]', '>3.2'])
    # Les colonnes que vous souhaitez avoir dans vos DataFrames cross_tab
    colonnes_desirees = [']0;3]', ']3;6]', ']6;18]', ']18;54]', ']54;162]', '>162']
    
    # Pour chaque DataFrame cross_tab, assurez-vous que les colonnes désirées existent et remplissez-les de zéros si elles sont manquantes.
    def ajouter_colonnes_manquantes(cross_tab):
        for colonne in colonnes_desirees:
            if colonne not in cross_tab.columns:
                cross_tab[colonne] = 0  # Ajoutez la colonne manquante et remplissez-la de zéros
    
    # Appelez cette fonction pour chaque DataFrame cross_tab
    ajouter_colonnes_manquantes(cross_tab21)
    ajouter_colonnes_manquantes(cross_tab32)
    ajouter_colonnes_manquantes(cross_tab43)
    ajouter_colonnes_manquantes(cross_tab54)
    ajouter_colonnes_manquantes(cross_tab65)
    ajouter_colonnes_manquantes(cross_tab76)
    ajouter_colonnes_manquantes(cross_tab87)
    ajouter_colonnes_manquantes(cross_tab98)
    ajouter_colonnes_manquantes(cross_tab109)
    
    
    cross_tab21 = cross_tab21[[']0;3]', ']3;6]', ']6;18]', ']18;54]', ']54;162]', '>162']]
    cross_tab32 = cross_tab32[[']0;3]', ']3;6]', ']6;18]', ']18;54]', ']54;162]', '>162']]
    cross_tab43 = cross_tab43[[']0;3]', ']3;6]', ']6;18]', ']18;54]', ']54;162]', '>162']]
    cross_tab54 = cross_tab54[[']0;3]', ']3;6]', ']6;18]', ']18;54]', ']54;162]', '>162']]
    cross_tab65 = cross_tab65[[']0;3]', ']3;6]', ']6;18]', ']18;54]', ']54;162]', '>162']]
    cross_tab76 = cross_tab76[[']0;3]', ']3;6]', ']6;18]', ']18;54]', ']54;162]', '>162']]
    cross_tab87 = cross_tab87[[']0;3]', ']3;6]', ']6;18]', ']18;54]', ']54;162]', '>162']]
    cross_tab98 = cross_tab98[[']0;3]', ']3;6]', ']6;18]', ']18;54]', ']54;162]', '>162']]
    cross_tab109 = cross_tab109[[']0;3]', ']3;6]', ']6;18]', ']18;54]', ']54;162]', '>162']]
    import matplotlib.pyplot as plt
    
    # Liste des noms des tableaux croisés
    cross_tabs = [cross_tab21, cross_tab32, cross_tab43, cross_tab54, cross_tab65]
    
    # Définissez les couleurs pour chaque catégorie
    colors = ['#E69F00', '#56B4E9', '#009E73', '#F0E442', '#0072B2', '#D55E00']
    
    # Initialisez la variable pour gérer le nombre de graphiques par ligne
    graphs_per_row = 2
    
    # Calcul du nombre total de lignes nécessaires
    num_rows = len(cross_tabs) // graphs_per_row + (len(cross_tabs) % graphs_per_row > 0)
    
    # Créez la figure et les sous-graphiques
    fig, axes = plt.subplots(nrows=num_rows, ncols=graphs_per_row, figsize=(15, 6 * num_rows))
    plt.subplots_adjust(wspace=0.5, hspace=0.5)
    
    # Parcourez les tableaux croisés et créez les graphiques
    for i, cross_tab in enumerate(cross_tabs):
        row, col = i // graphs_per_row, i % graphs_per_row
        ax = cross_tab.plot(kind='bar', stacked=True, color=colors, ax=axes[row, col])
        ax.set_xlabel('Catégorie Variation')
        ax.set_ylabel('Fréquence')
        ax.set_title(f'Distribution des variations en log différence pour les souscriptions {i+2}_{i+1}')
        ax.legend(title='Catégorie Nombre moyen d\'actions par souscription', bbox_to_anchor=(1.05, 1), loc='upper left')
    
    # Affichez les graphiques
    plt.tight_layout()
    plt.show()
    
    df_log = df_log.merge(df_parcours, on=['ID du contact'], how='left') df_log21 = df_log[["Log_diff_actions_souscriptions_2_1", "Nombre moyen d'actions par souscription"]] df_log32 = df_log[["Log_diff_actions_souscriptions_3_2", "Nombre moyen d'actions par souscription"]] df_log43 = df_log[["Log_diff_actions_souscriptions_4_3", "Nombre moyen d'actions par souscription"]] df_log54 = df_log[["Log_diff_actions_souscriptions_5_4", "Nombre moyen d'actions par souscription"]] df_log65 = df_log[["Log_diff_actions_souscriptions_6_5", "Nombre moyen d'actions par souscription"]] df_log76 = df_log[["Log_diff_actions_souscriptions_7_6", "Nombre moyen d'actions par souscription"]] df_log87 = df_log[["Log_diff_actions_souscriptions_8_7", "Nombre moyen d'actions par souscription"]] df_log98 = df_log[["Log_diff_actions_souscriptions_9_8", "Nombre moyen d'actions par souscription"]] df_log109 = df_log[["Log_diff_actions_souscriptions_10_9", "Nombre moyen d'actions par souscription"]] import numpy as np # Créer une fonction pour attribuer des catégories en fonction de la valeur def categorize_variation(val): if val == 0: return '[0]' elif -0.2 < val < 0: return ']-0,2;0[' elif -0.4 < val <= -0.2: return ']-0.4;-0.2]' elif -0.8 < val <= -0.4: return ']-0.8;-0.4]' elif -1.6 < val <= -0.8: return ']-1.6;-0.8]' elif -3.2 < val <= -1.6: return ']-3.2;-1.6]' elif val < -3.2: return '<-3.2' elif 0 < val <= 0.2: return ']0;0.2]' elif 0.2 < val <= 0.4: return ']0.2;0.4]' elif 0.4 < val <= 0.8: return ']0.4;0.8]' elif 0.8 < val <= 1.6: return ']0.8;1.6]' elif 1.6 < val <= 3.2: return ']1.6;3.2]' elif val > 3.2: return '>3.2' df_log21['Catégorie variation'] = df_log21['Log_diff_actions_souscriptions_2_1'].apply(categorize_variation) df_log32['Catégorie variation'] = df_log32['Log_diff_actions_souscriptions_3_2'].apply(categorize_variation) df_log43['Catégorie variation'] = df_log43['Log_diff_actions_souscriptions_4_3'].apply(categorize_variation) df_log54['Catégorie variation'] = df_log54['Log_diff_actions_souscriptions_5_4'].apply(categorize_variation) df_log65['Catégorie variation'] = df_log65['Log_diff_actions_souscriptions_6_5'].apply(categorize_variation) df_log76['Catégorie variation'] = df_log76['Log_diff_actions_souscriptions_7_6'].apply(categorize_variation) df_log87['Catégorie variation'] = df_log87['Log_diff_actions_souscriptions_8_7'].apply(categorize_variation) df_log98['Catégorie variation'] = df_log98['Log_diff_actions_souscriptions_9_8'].apply(categorize_variation) df_log109['Catégorie variation'] = df_log109['Log_diff_actions_souscriptions_10_9'].apply(categorize_variation) def categorize_actions(val): if val <= 3: return ']0;3]' elif val <= 6: return ']3;6]' elif val <= 18: return ']6;18]' elif val <= 54: return ']18;54]' elif val <= 162: return ']54;162]' else: return '>162' df_log21['Catégorie Nombre moyen d\'actions par souscription'] = df_log21['Nombre moyen d\'actions par souscription'].apply(categorize_actions) df_log32['Catégorie Nombre moyen d\'actions par souscription'] = df_log32['Nombre moyen d\'actions par souscription'].apply(categorize_actions) df_log43['Catégorie Nombre moyen d\'actions par souscription'] = df_log43['Nombre moyen d\'actions par souscription'].apply(categorize_actions) df_log54['Catégorie Nombre moyen d\'actions par souscription'] = df_log54['Nombre moyen d\'actions par souscription'].apply(categorize_actions) df_log65['Catégorie Nombre moyen d\'actions par souscription'] = df_log65['Nombre moyen d\'actions par souscription'].apply(categorize_actions) df_log76['Catégorie Nombre moyen d\'actions par souscription'] = df_log76['Nombre moyen d\'actions par souscription'].apply(categorize_actions) df_log87['Catégorie Nombre moyen d\'actions par souscription'] = df_log87['Nombre moyen d\'actions par souscription'].apply(categorize_actions) df_log98['Catégorie Nombre moyen d\'actions par souscription'] = df_log98['Nombre moyen d\'actions par souscription'].apply(categorize_actions) df_log109['Catégorie Nombre moyen d\'actions par souscription'] = df_log109['Nombre moyen d\'actions par souscription'].apply(categorize_actions) cross_tab21 = pd.crosstab(df_log21['Catégorie variation'], df_log21['Catégorie Nombre moyen d\'actions par souscription']) cross_tab32 = pd.crosstab(df_log32['Catégorie variation'], df_log32['Catégorie Nombre moyen d\'actions par souscription']) cross_tab43 = pd.crosstab(df_log43['Catégorie variation'], df_log43['Catégorie Nombre moyen d\'actions par souscription']) cross_tab54 = pd.crosstab(df_log54['Catégorie variation'], df_log54['Catégorie Nombre moyen d\'actions par souscription']) cross_tab65 = pd.crosstab(df_log65['Catégorie variation'], df_log65['Catégorie Nombre moyen d\'actions par souscription']) cross_tab76 = pd.crosstab(df_log76['Catégorie variation'], df_log76['Catégorie Nombre moyen d\'actions par souscription']) cross_tab87 = pd.crosstab(df_log87['Catégorie variation'], df_log87['Catégorie Nombre moyen d\'actions par souscription']) cross_tab98 = pd.crosstab(df_log98['Catégorie variation'], df_log98['Catégorie Nombre moyen d\'actions par souscription']) cross_tab109 = pd.crosstab(df_log109['Catégorie variation'], df_log109['Catégorie Nombre moyen d\'actions par souscription']) cross_tab21 = cross_tab21.reindex(['<-3.2', ']-3.2;-1.6]', ']-1.6;-0.8]', ']-0.8;-0.4]', ']-0.4;-0.2]',']-0,2;0[', '[0]', ']0;0.2]', ']0.2;0.4]', ']0.4;0.8]', ']0.8;1.6]', ']1.6;3.2]', '>3.2']) cross_tab32 = cross_tab32.reindex(['<-3.2', ']-3.2;-1.6]', ']-1.6;-0.8]', ']-0.8;-0.4]', ']-0.4;-0.2]',']-0,2;0[', '[0]', ']0;0.2]', ']0.2;0.4]', ']0.4;0.8]', ']0.8;1.6]', ']1.6;3.2]', '>3.2']) cross_tab54 = cross_tab54.reindex(['<-3.2', ']-3.2;-1.6]', ']-1.6;-0.8]', ']-0.8;-0.4]', ']-0.4;-0.2]',']-0,2;0[', '[0]', ']0;0.2]', ']0.2;0.4]', ']0.4;0.8]', ']0.8;1.6]', ']1.6;3.2]', '>3.2']) cross_tab65 = cross_tab65.reindex(['<-3.2', ']-3.2;-1.6]', ']-1.6;-0.8]', ']-0.8;-0.4]', ']-0.4;-0.2]',']-0,2;0[', '[0]', ']0;0.2]', ']0.2;0.4]', ']0.4;0.8]', ']0.8;1.6]', ']1.6;3.2]', '>3.2']) cross_tab76 = cross_tab76.reindex(['<-3.2', ']-3.2;-1.6]', ']-1.6;-0.8]', ']-0.8;-0.4]', ']-0.4;-0.2]',']-0,2;0[', '[0]', ']0;0.2]', ']0.2;0.4]', ']0.4;0.8]', ']0.8;1.6]', ']1.6;3.2]', '>3.2']) cross_tab87 = cross_tab87.reindex(['<-3.2', ']-3.2;-1.6]', ']-1.6;-0.8]', ']-0.8;-0.4]', ']-0.4;-0.2]',']-0,2;0[', '[0]', ']0;0.2]', ']0.2;0.4]', ']0.4;0.8]', ']0.8;1.6]', ']1.6;3.2]', '>3.2']) cross_tab98 = cross_tab98.reindex(['<-3.2', ']-3.2;-1.6]', ']-1.6;-0.8]', ']-0.8;-0.4]', ']-0.4;-0.2]',']-0,2;0[', '[0]', ']0;0.2]', ']0.2;0.4]', ']0.4;0.8]', ']0.8;1.6]', ']1.6;3.2]', '>3.2']) cross_tab109 = cross_tab109.reindex(['<-3.2', ']-3.2;-1.6]', ']-1.6;-0.8]', ']-0.8;-0.4]', ']-0.4;-0.2]',']-0,2;0[', '[0]', ']0;0.2]', ']0.2;0.4]', ']0.4;0.8]', ']0.8;1.6]', ']1.6;3.2]', '>3.2']) # Les colonnes que vous souhaitez avoir dans vos DataFrames cross_tab colonnes_desirees = [']0;3]', ']3;6]', ']6;18]', ']18;54]', ']54;162]', '>162'] # Pour chaque DataFrame cross_tab, assurez-vous que les colonnes désirées existent et remplissez-les de zéros si elles sont manquantes. def ajouter_colonnes_manquantes(cross_tab): for colonne in colonnes_desirees: if colonne not in cross_tab.columns: cross_tab[colonne] = 0 # Ajoutez la colonne manquante et remplissez-la de zéros # Appelez cette fonction pour chaque DataFrame cross_tab ajouter_colonnes_manquantes(cross_tab21) ajouter_colonnes_manquantes(cross_tab32) ajouter_colonnes_manquantes(cross_tab43) ajouter_colonnes_manquantes(cross_tab54) ajouter_colonnes_manquantes(cross_tab65) ajouter_colonnes_manquantes(cross_tab76) ajouter_colonnes_manquantes(cross_tab87) ajouter_colonnes_manquantes(cross_tab98) ajouter_colonnes_manquantes(cross_tab109) cross_tab21 = cross_tab21[[']0;3]', ']3;6]', ']6;18]', ']18;54]', ']54;162]', '>162']] cross_tab32 = cross_tab32[[']0;3]', ']3;6]', ']6;18]', ']18;54]', ']54;162]', '>162']] cross_tab43 = cross_tab43[[']0;3]', ']3;6]', ']6;18]', ']18;54]', ']54;162]', '>162']] cross_tab54 = cross_tab54[[']0;3]', ']3;6]', ']6;18]', ']18;54]', ']54;162]', '>162']] cross_tab65 = cross_tab65[[']0;3]', ']3;6]', ']6;18]', ']18;54]', ']54;162]', '>162']] cross_tab76 = cross_tab76[[']0;3]', ']3;6]', ']6;18]', ']18;54]', ']54;162]', '>162']] cross_tab87 = cross_tab87[[']0;3]', ']3;6]', ']6;18]', ']18;54]', ']54;162]', '>162']] cross_tab98 = cross_tab98[[']0;3]', ']3;6]', ']6;18]', ']18;54]', ']54;162]', '>162']] cross_tab109 = cross_tab109[[']0;3]', ']3;6]', ']6;18]', ']18;54]', ']54;162]', '>162']] import matplotlib.pyplot as plt # Liste des noms des tableaux croisés cross_tabs = [cross_tab21, cross_tab32, cross_tab43, cross_tab54, cross_tab65] # Définissez les couleurs pour chaque catégorie colors = ['#E69F00', '#56B4E9', '#009E73', '#F0E442', '#0072B2', '#D55E00'] # Initialisez la variable pour gérer le nombre de graphiques par ligne graphs_per_row = 2 # Calcul du nombre total de lignes nécessaires num_rows = len(cross_tabs) // graphs_per_row + (len(cross_tabs) % graphs_per_row > 0) # Créez la figure et les sous-graphiques fig, axes = plt.subplots(nrows=num_rows, ncols=graphs_per_row, figsize=(15, 6 * num_rows)) plt.subplots_adjust(wspace=0.5, hspace=0.5) # Parcourez les tableaux croisés et créez les graphiques for i, cross_tab in enumerate(cross_tabs): row, col = i // graphs_per_row, i % graphs_per_row ax = cross_tab.plot(kind='bar', stacked=True, color=colors, ax=axes[row, col]) ax.set_xlabel('Catégorie Variation') ax.set_ylabel('Fréquence') ax.set_title(f'Distribution des variations en log différence pour les souscriptions {i+2}_{i+1}') ax.legend(title='Catégorie Nombre moyen d\'actions par souscription', bbox_to_anchor=(1.05, 1), loc='upper left') # Affichez les graphiques plt.tight_layout() plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    
    
    In [ ]:
    Copied!
    # Liste des noms des tableaux croisés
    cross_tabs = [cross_tab76, cross_tab87, cross_tab98, cross_tab109]
    
    # Définissez les couleurs pour chaque catégorie
    colors = ['#E69F00', '#56B4E9', '#009E73', '#F0E442', '#0072B2', '#D55E00']
    
    # Initialisez la variable pour gérer le nombre de graphiques par ligne
    graphs_per_row = 2
    
    # Calcul du nombre total de lignes nécessaires
    num_rows = len(cross_tabs) // graphs_per_row + (len(cross_tabs) % graphs_per_row > 0)
    
    # Créez la figure et les sous-graphiques
    fig, axes = plt.subplots(nrows=num_rows, ncols=graphs_per_row, figsize=(15, 6 * num_rows))
    plt.subplots_adjust(wspace=0.5, hspace=0.5)
    
    # Parcourez les tableaux croisés et créez les graphiques
    for i, cross_tab in enumerate(cross_tabs):
        row, col = i // graphs_per_row, i % graphs_per_row
        ax = cross_tab.plot(kind='bar', stacked=True, color=colors, ax=axes[row, col])
        ax.set_xlabel('Catégorie Variation')
        ax.set_ylabel('Fréquence')
        ax.set_title(f'Distribution des variations en log différence pour les souscriptions {i+7}_{i+6}')
        ax.legend(title='Catégorie Nombre moyen d\'actions par souscription', bbox_to_anchor=(1.05, 1), loc='upper left')
    
    # Affichez les graphiques
    plt.tight_layout()
    plt.show()
    
    # Liste des noms des tableaux croisés cross_tabs = [cross_tab76, cross_tab87, cross_tab98, cross_tab109] # Définissez les couleurs pour chaque catégorie colors = ['#E69F00', '#56B4E9', '#009E73', '#F0E442', '#0072B2', '#D55E00'] # Initialisez la variable pour gérer le nombre de graphiques par ligne graphs_per_row = 2 # Calcul du nombre total de lignes nécessaires num_rows = len(cross_tabs) // graphs_per_row + (len(cross_tabs) % graphs_per_row > 0) # Créez la figure et les sous-graphiques fig, axes = plt.subplots(nrows=num_rows, ncols=graphs_per_row, figsize=(15, 6 * num_rows)) plt.subplots_adjust(wspace=0.5, hspace=0.5) # Parcourez les tableaux croisés et créez les graphiques for i, cross_tab in enumerate(cross_tabs): row, col = i // graphs_per_row, i % graphs_per_row ax = cross_tab.plot(kind='bar', stacked=True, color=colors, ax=axes[row, col]) ax.set_xlabel('Catégorie Variation') ax.set_ylabel('Fréquence') ax.set_title(f'Distribution des variations en log différence pour les souscriptions {i+7}_{i+6}') ax.legend(title='Catégorie Nombre moyen d\'actions par souscription', bbox_to_anchor=(1.05, 1), loc='upper left') # Affichez les graphiques plt.tight_layout() plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, HTML
    
    
    # Insérer un saut de page
    #display(HTML("<div style='page-break-before: always;'></div>"))
    
    # Afficher un titre centré avec une taille de police plus grande
    display(HTML('<center><h2><u>Création de reçus fiscaux</u></h2></center>'))
    
    from IPython.display import display, HTML # Insérer un saut de page #display(HTML("
    ")) # Afficher un titre centré avec une taille de police plus grande display(HTML('

    Création de reçus fiscaux

    '))

    Création de reçus fiscaux

    In [ ]:
    Copied!
    import pandas as pd
    
    df_RFcrée = df2["A fait l'objet d'un reçu fiscal"].value_counts().reset_index()
    df_RFcrée.columns = ['catégories', 'Nombre']
    
    # Convertir la colonne 'catégories' en type chaîne de caractères
    df_RFcrée['catégories'] = df_RFcrée['catégories'].astype(str)
    
    # Remplacer les valeurs de la colonne 'catégories'
    df_RFcrée['catégories'] = df_RFcrée['catégories'].replace({'1': 'crée', '0': 'non crée'})
    
    
    import matplotlib.pyplot as plt
    
    # Calculer le total des nombres
    total = df_RFcrée['Nombre'].sum()
    
    # Calculer le pourcentage de chaque catégorie
    df_RFcrée['Pourcentage'] = df_RFcrée['Nombre'] / total * 100
    
    # Créer le pie chart
    plt.figure(figsize=(8, 6))
    plt.pie(df_RFcrée['Nombre'], labels=df_RFcrée['catégories'], autopct='%1.1f%%')
    plt.title("Répartition des catégories de reçus fiscaux")
    
    # Afficher les étiquettes de données en nombre absolu et en pourcentage
    labels = [f"{n} ({p:.1f}%)" for n, p in zip(df_RFcrée['Nombre'], df_RFcrée['Pourcentage'])]
    plt.legend(labels, loc='best')
    
    # Afficher le pie chart
    plt.show()
    
    import pandas as pd df_RFcrée = df2["A fait l'objet d'un reçu fiscal"].value_counts().reset_index() df_RFcrée.columns = ['catégories', 'Nombre'] # Convertir la colonne 'catégories' en type chaîne de caractères df_RFcrée['catégories'] = df_RFcrée['catégories'].astype(str) # Remplacer les valeurs de la colonne 'catégories' df_RFcrée['catégories'] = df_RFcrée['catégories'].replace({'1': 'crée', '0': 'non crée'}) import matplotlib.pyplot as plt # Calculer le total des nombres total = df_RFcrée['Nombre'].sum() # Calculer le pourcentage de chaque catégorie df_RFcrée['Pourcentage'] = df_RFcrée['Nombre'] / total * 100 # Créer le pie chart plt.figure(figsize=(8, 6)) plt.pie(df_RFcrée['Nombre'], labels=df_RFcrée['catégories'], autopct='%1.1f%%') plt.title("Répartition des catégories de reçus fiscaux") # Afficher les étiquettes de données en nombre absolu et en pourcentage labels = [f"{n} ({p:.1f}%)" for n, p in zip(df_RFcrée['Nombre'], df_RFcrée['Pourcentage'])] plt.legend(labels, loc='best') # Afficher le pie chart plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Clé de lecture : Sur toutes les souscriptions qu'il y a eu, 13,5% n'ont pas fait l'objet d'un reçu fiscal</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Clé de lecture : Sur toutes les souscriptions qu'il y a eu, 13,5% n'ont pas fait l'objet d'un reçu fiscal

    "))

    Clé de lecture : Sur toutes les souscriptions qu'il y a eu, 13,5% n'ont pas fait l'objet d'un reçu fiscal

    In [ ]:
    Copied!
    df2.loc[:, "multi-casquette ?"] = df2.apply(lambda row: "Actionnaire-donateur" if row["Actionnaire ?"] == 1 and (row["Donateur N"] == 1 or row['RFM-Date Dernier Don'] >= twenty4_months_ago)  and row["adhérent N"] == 0 and row['adhérent N-1'] == 0
                                                else "Actionnaire-adhérent" if row["Actionnaire ?"] == 1 and (row["adhérent N"] == 1 or row['adhérent N-1'] == 1) and row["Donateur N"] == 0 and row['RFM-Date Dernier Don'] < twenty4_months_ago
                                                else "Triple-engagement" if row["Actionnaire ?"] == 1 and (row["adhérent N"] == 1 or row['adhérent N-1'] == 1) and (row["Donateur N"] == 1 or row['RFM-Date Dernier Don'] >= twenty4_months_ago)
                                                else "Actionnaire uniquement", axis=1)
    
    df2.loc[:, 'multi-souscripteur ?'] = df2.duplicated(subset='ID du contact', keep=False)
    
    
    dummies = pd.get_dummies(df2["A fait l'objet d'un reçu fiscal"], prefix="A fait l'objet d'un reçu fiscal")
    
    # Concaténation des dummies avec le DataFrame d'origine
    df2 = pd.concat([df2, dummies], axis=1)
    colonnes_dummies = ["A fait l'objet d'un reçu fiscal_0", "A fait l'objet d'un reçu fiscal_1"]
    
    # Remplacement des valeurs True par 1 et False par 0 dans les colonnes de dummies
    df2[colonnes_dummies] = df2[colonnes_dummies].replace({True: 1, False: 0})
    df2['Nombre de souscriptions'] = df2['ID du contact'].map(df2['ID du contact'].value_counts())
    conditions = [
         (df2['Nombre de souscriptions'] < 2),
         (df2['Nombre de souscriptions'] <3),
         (df2['Nombre de souscriptions'] <=5),
         (df2['Nombre de souscriptions'] <=10),
    ]
    
    choices = ['1 souscription', "2 souscriptions" , "3 à 5 souscriptions","6 à 10 souscriptions"]
    
    df2['Catégories souscripteurs'] = np.select(conditions, choices, default='10 souscriptions et plus')
    
    df_RF = df2.sort_values(by='ID du contact')
    grouped_counts = df2.groupby('ID du contact')["A fait l'objet d'un reçu fiscal_1"].sum()
    df_RF = df_RF.merge(grouped_counts, on='ID du contact', suffixes=('', '_count'))
    df_RF["% reçu fiscal demandé"] = df_RF ["A fait l'objet d'un reçu fiscal_1_count"] / df_RF["Nombre de souscriptions"] * 100
    df_RF= df_RF.drop(["A fait l'objet d'un reçu fiscal_0", "A fait l'objet d'un reçu fiscal_1","A fait l'objet d'un reçu fiscal_1_count"], axis=1)
    df_RF = df_RF.drop_duplicates(subset = "ID du contact")
    
    conditions = [
        (df_RF ["% reçu fiscal demandé"] == 0),
        (df_RF ["% reçu fiscal demandé"] < 20),
        (df_RF ["% reçu fiscal demandé"] < 40),
        (df_RF ['% reçu fiscal demandé'] < 60),
        (df_RF ['% reçu fiscal demandé'] < 80),
        (df_RF ['% reçu fiscal demandé'] < 100)
    ]
    
    choices =["0 % de RF crées sur l'ensemble des soucriptions", "]0 - 20[ % de RF crées sur l'ensemble des soucriptions", "[20 - 40[ % de RF crées sur l'ensemble des soucriptions", "[40 - 60[ % de RF crées sur l'ensemble des soucriptions", "[60 - 80[ % de RF crées sur l'ensemble des soucriptions", "[80 - 100[ % de RF crées sur l'ensemble des soucriptions"]
    df_RF['catégories des demandeurs de RF'] = np.select(conditions, choices, default="100 % de RF crées sur l'ensemble des soucriptions")
    
    df2.loc[:, "multi-casquette ?"] = df2.apply(lambda row: "Actionnaire-donateur" if row["Actionnaire ?"] == 1 and (row["Donateur N"] == 1 or row['RFM-Date Dernier Don'] >= twenty4_months_ago) and row["adhérent N"] == 0 and row['adhérent N-1'] == 0 else "Actionnaire-adhérent" if row["Actionnaire ?"] == 1 and (row["adhérent N"] == 1 or row['adhérent N-1'] == 1) and row["Donateur N"] == 0 and row['RFM-Date Dernier Don'] < twenty4_months_ago else "Triple-engagement" if row["Actionnaire ?"] == 1 and (row["adhérent N"] == 1 or row['adhérent N-1'] == 1) and (row["Donateur N"] == 1 or row['RFM-Date Dernier Don'] >= twenty4_months_ago) else "Actionnaire uniquement", axis=1) df2.loc[:, 'multi-souscripteur ?'] = df2.duplicated(subset='ID du contact', keep=False) dummies = pd.get_dummies(df2["A fait l'objet d'un reçu fiscal"], prefix="A fait l'objet d'un reçu fiscal") # Concaténation des dummies avec le DataFrame d'origine df2 = pd.concat([df2, dummies], axis=1) colonnes_dummies = ["A fait l'objet d'un reçu fiscal_0", "A fait l'objet d'un reçu fiscal_1"] # Remplacement des valeurs True par 1 et False par 0 dans les colonnes de dummies df2[colonnes_dummies] = df2[colonnes_dummies].replace({True: 1, False: 0}) df2['Nombre de souscriptions'] = df2['ID du contact'].map(df2['ID du contact'].value_counts()) conditions = [ (df2['Nombre de souscriptions'] < 2), (df2['Nombre de souscriptions'] <3), (df2['Nombre de souscriptions'] <=5), (df2['Nombre de souscriptions'] <=10), ] choices = ['1 souscription', "2 souscriptions" , "3 à 5 souscriptions","6 à 10 souscriptions"] df2['Catégories souscripteurs'] = np.select(conditions, choices, default='10 souscriptions et plus') df_RF = df2.sort_values(by='ID du contact') grouped_counts = df2.groupby('ID du contact')["A fait l'objet d'un reçu fiscal_1"].sum() df_RF = df_RF.merge(grouped_counts, on='ID du contact', suffixes=('', '_count')) df_RF["% reçu fiscal demandé"] = df_RF ["A fait l'objet d'un reçu fiscal_1_count"] / df_RF["Nombre de souscriptions"] * 100 df_RF= df_RF.drop(["A fait l'objet d'un reçu fiscal_0", "A fait l'objet d'un reçu fiscal_1","A fait l'objet d'un reçu fiscal_1_count"], axis=1) df_RF = df_RF.drop_duplicates(subset = "ID du contact") conditions = [ (df_RF ["% reçu fiscal demandé"] == 0), (df_RF ["% reçu fiscal demandé"] < 20), (df_RF ["% reçu fiscal demandé"] < 40), (df_RF ['% reçu fiscal demandé'] < 60), (df_RF ['% reçu fiscal demandé'] < 80), (df_RF ['% reçu fiscal demandé'] < 100) ] choices =["0 % de RF crées sur l'ensemble des soucriptions", "]0 - 20[ % de RF crées sur l'ensemble des soucriptions", "[20 - 40[ % de RF crées sur l'ensemble des soucriptions", "[40 - 60[ % de RF crées sur l'ensemble des soucriptions", "[60 - 80[ % de RF crées sur l'ensemble des soucriptions", "[80 - 100[ % de RF crées sur l'ensemble des soucriptions"] df_RF['catégories des demandeurs de RF'] = np.select(conditions, choices, default="100 % de RF crées sur l'ensemble des soucriptions")
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Nombres d'individus par catégories de demandeurs de RF (part des souscriptions qui ont fait l'objet d'un RF sur toutes leurs souscriptions)</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Nombres d'individus par catégories de demandeurs de RF (part des souscriptions qui ont fait l'objet d'un RF sur toutes leurs souscriptions)

    "))

    Nombres d'individus par catégories de demandeurs de RF (part des souscriptions qui ont fait l'objet d'un RF sur toutes leurs souscriptions)

    In [ ]:
    Copied!
    value_counts = df_RF["catégories des demandeurs de RF"].value_counts().reset_index()
    value_counts.columns = ["Catégories des demandeurs de RF", "Nombre d'individus"]
    categories_order = ["0 % de RF crées sur l'ensemble des soucriptions", "]0 - 20[ % de RF crées sur l'ensemble des soucriptions", "[20 - 40[ % de RF crées sur l'ensemble des soucriptions", "[40 - 60[ % de RF crées sur l'ensemble des soucriptions", "[60 - 80[ % de RF crées sur l'ensemble des soucriptions", "[80 - 100[ % de RF crées sur l'ensemble des soucriptions", "100 % de RF crées sur l'ensemble des soucriptions"]
    
    # Créer un DataFrame contenant toutes les catégories dans l'ordre spécifié
    categories_df = pd.DataFrame({"Catégories des demandeurs de RF": categories_order})
    
    # Fusionner les données avec la réindexation
    value_counts_sorted = categories_df.merge(value_counts, how="left")
    
    value_counts["Catégories des demandeurs de RF"] = value_counts["Catégories des demandeurs de RF"].astype(str)
    
    # Fusionner les données avec la réindexation
    value_counts_sorted = categories_df.merge(value_counts, how="left")
    
    value_counts = df_RF["catégories des demandeurs de RF"].value_counts().reset_index() value_counts.columns = ["Catégories des demandeurs de RF", "Nombre d'individus"] categories_order = ["0 % de RF crées sur l'ensemble des soucriptions", "]0 - 20[ % de RF crées sur l'ensemble des soucriptions", "[20 - 40[ % de RF crées sur l'ensemble des soucriptions", "[40 - 60[ % de RF crées sur l'ensemble des soucriptions", "[60 - 80[ % de RF crées sur l'ensemble des soucriptions", "[80 - 100[ % de RF crées sur l'ensemble des soucriptions", "100 % de RF crées sur l'ensemble des soucriptions"] # Créer un DataFrame contenant toutes les catégories dans l'ordre spécifié categories_df = pd.DataFrame({"Catégories des demandeurs de RF": categories_order}) # Fusionner les données avec la réindexation value_counts_sorted = categories_df.merge(value_counts, how="left") value_counts["Catégories des demandeurs de RF"] = value_counts["Catégories des demandeurs de RF"].astype(str) # Fusionner les données avec la réindexation value_counts_sorted = categories_df.merge(value_counts, how="left")
    In [ ]:
    Copied!
    import matplotlib.pyplot as plt
    import warnings
    warnings.filterwarnings("ignore")
    # Données pour l'histogramme
    categories = value_counts_sorted["Catégories des demandeurs de RF"]
    counts = value_counts_sorted["Nombre d'individus"]
    
    # Créer le graphique
    plt.figure(figsize=(8, 6))
    bars = plt.bar(categories, counts)
    
    # Incliner les noms des catégories et espacer les barres
    plt.xticks(rotation=45, ha='right')
    
    # Titre et étiquettes des axes
    plt.title("Nombre d'individus appartenant aux différentes catégories de demandeurs de RF ")
    plt.xlabel("")
    plt.ylabel("Nombre d'individus")
    
    # Ajouter les valeurs au-dessus de chaque barre
    for bar in bars:
        height = bar.get_height()
        plt.text(bar.get_x() + bar.get_width() / 2, height, height, ha='center', va='bottom')
    
    # Afficher l'histogramme
    plt.show()
    
    import matplotlib.pyplot as plt import warnings warnings.filterwarnings("ignore") # Données pour l'histogramme categories = value_counts_sorted["Catégories des demandeurs de RF"] counts = value_counts_sorted["Nombre d'individus"] # Créer le graphique plt.figure(figsize=(8, 6)) bars = plt.bar(categories, counts) # Incliner les noms des catégories et espacer les barres plt.xticks(rotation=45, ha='right') # Titre et étiquettes des axes plt.title("Nombre d'individus appartenant aux différentes catégories de demandeurs de RF ") plt.xlabel("") plt.ylabel("Nombre d'individus") # Ajouter les valeurs au-dessus de chaque barre for bar in bars: height = bar.get_height() plt.text(bar.get_x() + bar.get_width() / 2, height, height, ha='center', va='bottom') # Afficher l'histogramme plt.show()
    posx and posy should be finite values
    
    posx and posy should be finite values
    
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Clé de lecture : il y a eu 17 519 personnes qui ont demandé un reçu fiscal pour l'ensemble de leurs souscriptions (100 % de RF crées sur l'ensemble des souscriptions)</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Clé de lecture : il y a eu 17 519 personnes qui ont demandé un reçu fiscal pour l'ensemble de leurs souscriptions (100 % de RF crées sur l'ensemble des souscriptions)

    "))

    Clé de lecture : il y a eu 17 519 personnes qui ont demandé un reçu fiscal pour l'ensemble de leurs souscriptions (100 % de RF crées sur l'ensemble des souscriptions)

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Moyennes des parts de RF demandés sur l'ensemble des souscription individuelles par multi-souscripteurs ?</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Moyennes des parts de RF demandés sur l'ensemble des souscription individuelles par multi-souscripteurs ?

    "))

    Moyennes des parts de RF demandés sur l'ensemble des souscription individuelles par multi-souscripteurs ?

    In [ ]:
    Copied!
    df_RF_MS = df_RF.groupby("multi-souscripteur ?")["% reçu fiscal demandé"].mean().to_frame()
    df_RF_MS = df_RF_MS.round()
    df_RF_MS
    
    df_RF_MS = df_RF.groupby("multi-souscripteur ?")["% reçu fiscal demandé"].mean().to_frame() df_RF_MS = df_RF_MS.round() df_RF_MS
    Out[ ]:
    % reçu fiscal demandé
    multi-souscripteur ?
    False 77.0
    True 77.0
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Clé de lecture : Les multis souscripteurs ont demandé en moyenne un reçu fiscal pour 84 % de leurs souscriptions</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Clé de lecture : Les multis souscripteurs ont demandé en moyenne un reçu fiscal pour 84 % de leurs souscriptions

    "))

    Clé de lecture : Les multis souscripteurs ont demandé en moyenne un reçu fiscal pour 84 % de leurs souscriptions

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Moyennes des parts de RF demandés sur l'ensemble des souscription individuelles par catégories d'âge</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Moyennes des parts de RF demandés sur l'ensemble des souscription individuelles par catégories d'âge

    "))

    Moyennes des parts de RF demandés sur l'ensemble des souscription individuelles par catégories d'âge

    In [ ]:
    Copied!
    df_RF_age = df_RF.groupby("catégories âge")["% reçu fiscal demandé"].mean().to_frame()
    df_RF_age.round()
    
    df_RF_age = df_RF.groupby("catégories âge")["% reçu fiscal demandé"].mean().to_frame() df_RF_age.round()
    Out[ ]:
    % reçu fiscal demandé
    catégories âge
    0-25 ans 77.0
    25-40 ans 77.0
    40-60 ans 77.0
    60 ans et plus 76.0
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Moyennes des parts de RF demandés sur l'ensemble des souscription individuelles par ancienneté de l'actionnaire</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Moyennes des parts de RF demandés sur l'ensemble des souscription individuelles par ancienneté de l'actionnaire

    "))

    Moyennes des parts de RF demandés sur l'ensemble des souscription individuelles par ancienneté de l'actionnaire

    In [ ]:
    Copied!
    df_RF_ancienneté = df_RF.groupby("ancienneté actionnaires")["% reçu fiscal demandé"].mean().to_frame()
    df_RF_ancienneté = df_RF_ancienneté.reindex(index=ordre_categories_ancienneté)
    df_RF_ancienneté.round()
    
    df_RF_ancienneté = df_RF.groupby("ancienneté actionnaires")["% reçu fiscal demandé"].mean().to_frame() df_RF_ancienneté = df_RF_ancienneté.reindex(index=ordre_categories_ancienneté) df_RF_ancienneté.round()
    Out[ ]:
    % reçu fiscal demandé
    ancienneté actionnaires
    Nouvel actionnaire depuis 2017 ou plus 76.0
    Nouvel actionnaire entre 2012 à 2017 77.0
    Nouvel actionnaire en 2012 ou moins 77.0
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Moyennes des parts de RF demandés sur l'ensemble des souscription individuelles par catégories de souscripteurs</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Moyennes des parts de RF demandés sur l'ensemble des souscription individuelles par catégories de souscripteurs

    "))

    Moyennes des parts de RF demandés sur l'ensemble des souscription individuelles par catégories de souscripteurs

    In [ ]:
    Copied!
    df_RF_catsous= df_RF.groupby('Catégories souscripteurs')["% reçu fiscal demandé"].mean().to_frame()
    df_RF_catsous = df_RF_catsous.reindex(index=ordre_categories)
    df_RF_catsous.round()
    
    df_RF_catsous= df_RF.groupby('Catégories souscripteurs')["% reçu fiscal demandé"].mean().to_frame() df_RF_catsous = df_RF_catsous.reindex(index=ordre_categories) df_RF_catsous.round()
    Out[ ]:
    % reçu fiscal demandé
    Catégories souscripteurs
    1 souscription 77.0
    2 souscriptions 77.0
    3 à 5 souscriptions 77.0
    6 à 10 souscriptions 77.0
    10 souscriptions et plus 76.0
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Insérer un saut de page
    display(HTML("<div style='page-break-before: always;'></div>"))
    
    
    display(HTML('<center><h2><u>Affectation des souscriptions</u></h2></center>'))
    
    from IPython.display import display, Markdown, HTML # Insérer un saut de page display(HTML("
    ")) display(HTML('

    Affectation des souscriptions

    '))

    Affectation des souscriptions

    In [ ]:
    Copied!
    df2['Type affectation'] = df2["Affectation"].apply(lambda x: 'dédié région' if str(x).startswith('Collecte')
                                                     else "non dédié " if str(x).startswith('Ensemble') else 'dédié projet')
    
    df2['Type affectation'] = df2["Affectation"].apply(lambda x: 'dédié région' if str(x).startswith('Collecte') else "non dédié " if str(x).startswith('Ensemble') else 'dédié projet')
    In [ ]:
    Copied!
    # Supposons que votre DataFrame s'appelle df2
    df_affectation= df2['Type affectation'].value_counts().reset_index()
    
    # Renommer les colonnes du tableau
    df_affectation.columns = ['Valeur', 'Nombre de correspondances']
    
    
    df_affectation
    
    # Supposons que votre DataFrame s'appelle df2 df_affectation= df2['Type affectation'].value_counts().reset_index() # Renommer les colonnes du tableau df_affectation.columns = ['Valeur', 'Nombre de correspondances'] df_affectation
    Out[ ]:
    Valeur Nombre de correspondances
    0 dédié projet 5785
    1 dédié région 5600
    2 non dédié 5502
    In [ ]:
    Copied!
    import matplotlib.pyplot as plt
    
    # Calculer les valeurs et les étiquettes pour le pie chart
    counts = df2['Type affectation'].value_counts()
    percentages = counts / counts.sum() * 100
    
    # Créer le pie chart
    plt.pie(counts, labels=counts.index, autopct='%1.1f%%', startangle=90)
    plt.title("Types d'affectation")
    
    
    
    # Afficher le graphique
    plt.show()
    
    import matplotlib.pyplot as plt # Calculer les valeurs et les étiquettes pour le pie chart counts = df2['Type affectation'].value_counts() percentages = counts / counts.sum() * 100 # Créer le pie chart plt.pie(counts, labels=counts.index, autopct='%1.1f%%', startangle=90) plt.title("Types d'affectation") # Afficher le graphique plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Répartition des affectations région</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Répartition des affectations région

    "))

    Répartition des affectations région

    In [ ]:
    Copied!
    df_région = df2[df2['Type affectation'] == 'dédié région'].copy()
    
    
    df_région['Affectation'] = df_région['Affectation'].str.replace('Collecte dédiée ', '')
    
    df_région['Affectation'] = df_région['Affectation'].str.replace('lorraine', 'LORRAINE')
    
    df_région= df_région['Affectation'].value_counts().reset_index()
    
    total_count = df_région['count'].sum()
    
    
    df_région['Part du total en %'] = df_région['count'] / total_count * 100
    
    # Calculer le total de chaque colonne
    total = df_région.sum()
    
    # Créer un nouveau DataFrame avec les totaux
    df_total = pd.DataFrame([total.values], columns=df_région.columns)
    
    # Renommer la nouvelle ligne avec le label "Total"
    df_total.at[0, 'Affectation'] = "Total"
    
    # Concaténer le DataFrame original avec le DataFrame des totaux
    df_région_total = pd.concat([df_région, df_total])
    
    # Afficher le DataFrame avec les totaux
    df_région_total
    
    df_région = df2[df2['Type affectation'] == 'dédié région'].copy() df_région['Affectation'] = df_région['Affectation'].str.replace('Collecte dédiée ', '') df_région['Affectation'] = df_région['Affectation'].str.replace('lorraine', 'LORRAINE') df_région= df_région['Affectation'].value_counts().reset_index() total_count = df_région['count'].sum() df_région['Part du total en %'] = df_région['count'] / total_count * 100 # Calculer le total de chaque colonne total = df_région.sum() # Créer un nouveau DataFrame avec les totaux df_total = pd.DataFrame([total.values], columns=df_région.columns) # Renommer la nouvelle ligne avec le label "Total" df_total.at[0, 'Affectation'] = "Total" # Concaténer le DataFrame original avec le DataFrame des totaux df_région_total = pd.concat([df_région, df_total]) # Afficher le DataFrame avec les totaux df_région_total
    Out[ ]:
    Affectation count Part du total en %
    0 - Île-de-France 282 5.035714
    1 - Poitou-Charentes 273 4.875000
    2 - Limousin 272 4.857143
    3 - Languedoc-Roussillon 267 4.767857
    4 - Midi-Pyrénées 264 4.714286
    5 - Nord-Pas-de-Calais 262 4.678571
    6 - Bourgogne 262 4.678571
    7 - Champagne-Ardenne 259 4.625000
    8 - Aquitaine 259 4.625000
    9 - Franche-Comté 254 4.535714
    10 - Bretagne 253 4.517857
    11 - Centre 252 4.500000
    12 - Rhône-Alpes 251 4.482143
    13 - Haute-Normandie 251 4.482143
    14 - Alsace 251 4.482143
    15 - Basse-Normandie 250 4.464286
    16 - Lorraine 249 4.446429
    17 - Picardie 248 4.428571
    18 - Provence-Alpes-Côte d'Azur 242 4.321429
    19 - Pays de la Loire 239 4.267857
    20 - Corse 234 4.178571
    21 - Auvergne 226 4.035714
    0 Total 5600 100.000000
    In [ ]:
    Copied!
    dummies = pd.get_dummies(df2['Type affectation'], prefix='Affectation')
    
    # Concaténation des dummies avec le DataFrame d'origine
    df2 = pd.concat([df2, dummies], axis=1)
    colonnes_dummies = ["Affectation_dédié région", 'Affectation_dédié projet', 'Affectation_non dédié ']
    
    # Remplacement des valeurs True par 1 et False par 0 dans les colonnes de dummies
    df2[colonnes_dummies] = df2[colonnes_dummies].replace({True: 1, False: 0})
    df2['Nombre de souscriptions'] = df2['ID du contact'].map(df2['ID du contact'].value_counts())
    df_affect = df2.sort_values(by='ID du contact')
    grouped_counts = df2.groupby('ID du contact')["Affectation_dédié région"].sum()
    grouped_countsDP = df2.groupby('ID du contact')["Affectation_dédié projet"].sum()
    grouped_countsND = df2.groupby('ID du contact')["Affectation_non dédié "].sum()
    df_affect = df_affect.merge(grouped_counts, on='ID du contact', suffixes=('', '_count'))
    df_affect = df_affect.merge(grouped_countsDP, on='ID du contact', suffixes=('', '_count'))
    df_affect = df_affect.merge(grouped_countsND, on='ID du contact', suffixes=('', '_count'))
    df_affect["% affec région"] = df_affect['Affectation_dédié région_count'] / df_affect["Nombre de souscriptions"] * 100
    df_affect["% affec projet"] = df_affect['Affectation_dédié projet_count'] / df_affect["Nombre de souscriptions"] * 100
    df_affect["% affec non-dédié"] = df_affect['Affectation_non dédié _count'] / df_affect["Nombre de souscriptions"] * 100
    
    df_affect= df_affect.drop(['Affectation_dédié projet', 'Affectation_dédié région', 'Affectation_dédié région_count', 'Affectation_non dédié ', 'Affectation_dédié projet_count','Affectation_non dédié _count'], axis=1)
    df_affect = df_affect.drop_duplicates(subset = "ID du contact")
    conditions = [
         (df_affect['Nombre de souscriptions'] < 2),
         (df_affect['Nombre de souscriptions'] <3),
         (df_affect['Nombre de souscriptions'] <=5),
         (df_affect['Nombre de souscriptions'] <=10),
    ]
    
    choices = ['1 souscription', "2 souscriptions" , "3 à 5 souscriptions","6 à 10 souscriptions"]
    
    df_affect['Catégories souscripteurs'] = np.select(conditions, choices, default='10 souscriptions et plus')
    
    dummies = pd.get_dummies(df2['Type affectation'], prefix='Affectation') # Concaténation des dummies avec le DataFrame d'origine df2 = pd.concat([df2, dummies], axis=1) colonnes_dummies = ["Affectation_dédié région", 'Affectation_dédié projet', 'Affectation_non dédié '] # Remplacement des valeurs True par 1 et False par 0 dans les colonnes de dummies df2[colonnes_dummies] = df2[colonnes_dummies].replace({True: 1, False: 0}) df2['Nombre de souscriptions'] = df2['ID du contact'].map(df2['ID du contact'].value_counts()) df_affect = df2.sort_values(by='ID du contact') grouped_counts = df2.groupby('ID du contact')["Affectation_dédié région"].sum() grouped_countsDP = df2.groupby('ID du contact')["Affectation_dédié projet"].sum() grouped_countsND = df2.groupby('ID du contact')["Affectation_non dédié "].sum() df_affect = df_affect.merge(grouped_counts, on='ID du contact', suffixes=('', '_count')) df_affect = df_affect.merge(grouped_countsDP, on='ID du contact', suffixes=('', '_count')) df_affect = df_affect.merge(grouped_countsND, on='ID du contact', suffixes=('', '_count')) df_affect["% affec région"] = df_affect['Affectation_dédié région_count'] / df_affect["Nombre de souscriptions"] * 100 df_affect["% affec projet"] = df_affect['Affectation_dédié projet_count'] / df_affect["Nombre de souscriptions"] * 100 df_affect["% affec non-dédié"] = df_affect['Affectation_non dédié _count'] / df_affect["Nombre de souscriptions"] * 100 df_affect= df_affect.drop(['Affectation_dédié projet', 'Affectation_dédié région', 'Affectation_dédié région_count', 'Affectation_non dédié ', 'Affectation_dédié projet_count','Affectation_non dédié _count'], axis=1) df_affect = df_affect.drop_duplicates(subset = "ID du contact") conditions = [ (df_affect['Nombre de souscriptions'] < 2), (df_affect['Nombre de souscriptions'] <3), (df_affect['Nombre de souscriptions'] <=5), (df_affect['Nombre de souscriptions'] <=10), ] choices = ['1 souscription', "2 souscriptions" , "3 à 5 souscriptions","6 à 10 souscriptions"] df_affect['Catégories souscripteurs'] = np.select(conditions, choices, default='10 souscriptions et plus')
    In [ ]:
    Copied!
    df_affect.rename(columns={'Territoire Terre de Liens': 'Territoire d\'habitation renseigné'}, inplace=True)
    
    df_affect.rename(columns={'Territoire Terre de Liens': 'Territoire d\'habitation renseigné'}, inplace=True)
    In [ ]:
    Copied!
    df_affect_nbsous = df_affect.groupby('Catégories souscripteurs')['% affec région'].mean().to_frame()
    df_affect_catage = df_affect.groupby('catégories âge')['% affec région'].mean().to_frame()
    df_affect_MC = df_affect.groupby('multi-casquette ?')['% affec région'].mean().to_frame()
    df_affect_ancienneté = df_affect.groupby('ancienneté actionnaires')['% affec région'].mean().to_frame()
    df_affect_MS= df_affect.groupby('multi-souscripteur ?')['% affec région'].mean().to_frame()
    
    # Calculate means for '% affec projet' by different categories
    df_affect_nbsous_proj = df_affect.groupby('Catégories souscripteurs')['% affec projet'].mean().to_frame()
    df_affect_catage_proj = df_affect.groupby('catégories âge')['% affec projet'].mean().to_frame()
    df_affect_MC_proj = df_affect.groupby('multi-casquette ?')['% affec projet'].mean().to_frame()
    df_affect_ancienneté_proj = df_affect.groupby('ancienneté actionnaires')['% affec projet'].mean().to_frame()
    df_affect_MS_proj= df_affect.groupby('multi-souscripteur ?')['% affec projet'].mean().to_frame()
    # Calculate means for '% affec non-dédié' by different categories
    df_affect_nbsous_non_dedie = df_affect.groupby('Catégories souscripteurs')['% affec non-dédié'].mean().to_frame()
    df_affect_catage_non_dedie = df_affect.groupby('catégories âge')['% affec non-dédié'].mean().to_frame()
    df_affect_MC_non_dedie = df_affect.groupby('multi-casquette ?')['% affec non-dédié'].mean().to_frame()
    df_affect_ancienneté_non_dedie = df_affect.groupby('ancienneté actionnaires')['% affec non-dédié'].mean().to_frame()
    df_affect_MS_non_dedie = df_affect.groupby('multi-souscripteur ?')['% affec non-dédié'].mean().to_frame()
    
    
    # Merge DataFrames for '% affec région', '% affec projet', and '% affec non-dédié' for each category
    merged_df_nbsous = df_affect_nbsous.merge(df_affect_nbsous_proj, on='Catégories souscripteurs')
    merged_df_nbsous = merged_df_nbsous.merge(df_affect_nbsous_non_dedie, on='Catégories souscripteurs')
    
    merged_df_catage = df_affect_catage.merge(df_affect_catage_proj, on='catégories âge')
    merged_df_catage = merged_df_catage.merge(df_affect_catage_non_dedie, on='catégories âge')
    
    merged_df_MC = df_affect_MC.merge(df_affect_MC_proj, on='multi-casquette ?')
    merged_df_MC = merged_df_MC.merge(df_affect_MC_non_dedie, on='multi-casquette ?')
    
    merged_df_ancienneté = df_affect_ancienneté.merge(df_affect_ancienneté_proj, on='ancienneté actionnaires')
    merged_df_ancienneté = merged_df_ancienneté.merge(df_affect_ancienneté_non_dedie, on='ancienneté actionnaires')
    merged_df_MS = df_affect_MS.merge(df_affect_MS_proj, on='multi-souscripteur ?')
    merged_df_MS = merged_df_MS.merge(df_affect_MS_non_dedie, on='multi-souscripteur ?')
    
    df_affect_nbsous = df_affect.groupby('Catégories souscripteurs')['% affec région'].mean().to_frame() df_affect_catage = df_affect.groupby('catégories âge')['% affec région'].mean().to_frame() df_affect_MC = df_affect.groupby('multi-casquette ?')['% affec région'].mean().to_frame() df_affect_ancienneté = df_affect.groupby('ancienneté actionnaires')['% affec région'].mean().to_frame() df_affect_MS= df_affect.groupby('multi-souscripteur ?')['% affec région'].mean().to_frame() # Calculate means for '% affec projet' by different categories df_affect_nbsous_proj = df_affect.groupby('Catégories souscripteurs')['% affec projet'].mean().to_frame() df_affect_catage_proj = df_affect.groupby('catégories âge')['% affec projet'].mean().to_frame() df_affect_MC_proj = df_affect.groupby('multi-casquette ?')['% affec projet'].mean().to_frame() df_affect_ancienneté_proj = df_affect.groupby('ancienneté actionnaires')['% affec projet'].mean().to_frame() df_affect_MS_proj= df_affect.groupby('multi-souscripteur ?')['% affec projet'].mean().to_frame() # Calculate means for '% affec non-dédié' by different categories df_affect_nbsous_non_dedie = df_affect.groupby('Catégories souscripteurs')['% affec non-dédié'].mean().to_frame() df_affect_catage_non_dedie = df_affect.groupby('catégories âge')['% affec non-dédié'].mean().to_frame() df_affect_MC_non_dedie = df_affect.groupby('multi-casquette ?')['% affec non-dédié'].mean().to_frame() df_affect_ancienneté_non_dedie = df_affect.groupby('ancienneté actionnaires')['% affec non-dédié'].mean().to_frame() df_affect_MS_non_dedie = df_affect.groupby('multi-souscripteur ?')['% affec non-dédié'].mean().to_frame() # Merge DataFrames for '% affec région', '% affec projet', and '% affec non-dédié' for each category merged_df_nbsous = df_affect_nbsous.merge(df_affect_nbsous_proj, on='Catégories souscripteurs') merged_df_nbsous = merged_df_nbsous.merge(df_affect_nbsous_non_dedie, on='Catégories souscripteurs') merged_df_catage = df_affect_catage.merge(df_affect_catage_proj, on='catégories âge') merged_df_catage = merged_df_catage.merge(df_affect_catage_non_dedie, on='catégories âge') merged_df_MC = df_affect_MC.merge(df_affect_MC_proj, on='multi-casquette ?') merged_df_MC = merged_df_MC.merge(df_affect_MC_non_dedie, on='multi-casquette ?') merged_df_ancienneté = df_affect_ancienneté.merge(df_affect_ancienneté_proj, on='ancienneté actionnaires') merged_df_ancienneté = merged_df_ancienneté.merge(df_affect_ancienneté_non_dedie, on='ancienneté actionnaires') merged_df_MS = df_affect_MS.merge(df_affect_MS_proj, on='multi-souscripteur ?') merged_df_MS = merged_df_MS.merge(df_affect_MS_non_dedie, on='multi-souscripteur ?')
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h2>Part moyenne des affectations  sur toutes les souscriptions par personne</h2>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Part moyenne des affectations sur toutes les souscriptions par personne

    "))

    Part moyenne des affectations sur toutes les souscriptions par personne

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Part moyenne des affectations par multi-souscrippteurs ou pas</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Part moyenne des affectations par multi-souscrippteurs ou pas

    "))

    Part moyenne des affectations par multi-souscrippteurs ou pas

    In [ ]:
    Copied!
    merged_df_MS 
    
    merged_df_MS
    Out[ ]:
    % affec région % affec projet % affec non-dédié
    multi-souscripteur ?
    False 33.178468 34.668376 32.153156
    True 33.019107 34.253755 32.727138
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Part moyenne des affectations par catégories de souscripteurs</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Part moyenne des affectations par catégories de souscripteurs

    "))

    Part moyenne des affectations par catégories de souscripteurs

    In [ ]:
    Copied!
    merged_df_nbsous["Total"] = merged_df_nbsous["% affec région"]+ merged_df_nbsous["% affec projet"]+ merged_df_nbsous["% affec non-dédié"]
    ordre_categories = ['1 souscription', '2 souscriptions', '3 à 5 souscriptions', '6 à 10 souscriptions', '10 souscriptions et plus']
    merged_df_nbsous = merged_df_nbsous.reindex(ordre_categories)
    merged_df_nbsous = merged_df_nbsous.round()
    merged_df_nbsous
    
    merged_df_nbsous["Total"] = merged_df_nbsous["% affec région"]+ merged_df_nbsous["% affec projet"]+ merged_df_nbsous["% affec non-dédié"] ordre_categories = ['1 souscription', '2 souscriptions', '3 à 5 souscriptions', '6 à 10 souscriptions', '10 souscriptions et plus'] merged_df_nbsous = merged_df_nbsous.reindex(ordre_categories) merged_df_nbsous = merged_df_nbsous.round() merged_df_nbsous
    Out[ ]:
    % affec région % affec projet % affec non-dédié Total
    Catégories souscripteurs
    1 souscription 33.0 35.0 32.0 100.0
    2 souscriptions 33.0 35.0 33.0 100.0
    3 à 5 souscriptions 34.0 34.0 32.0 100.0
    6 à 10 souscriptions 32.0 34.0 34.0 100.0
    10 souscriptions et plus 34.0 31.0 35.0 100.0
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Clé de lecture : les personnes ayant eu 3 à 5 soucriptions les ont dédiées en moyenne à 33 % à une région. On remarque que les mono-souscripteurs ont tendance à affecter leurs souscritpions aux fermes</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Clé de lecture : les personnes ayant eu 3 à 5 soucriptions les ont dédiées en moyenne à 33 % à une région. On remarque que les mono-souscripteurs ont tendance à affecter leurs souscritpions aux fermes

    "))

    Clé de lecture : les personnes ayant eu 3 à 5 soucriptions les ont dédiées en moyenne à 33 % à une région. On remarque que les mono-souscripteurs ont tendance à affecter leurs souscritpions aux fermes

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Part moyenne des affectations par catégories d'âge</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Part moyenne des affectations par catégories d'âge

    "))

    Part moyenne des affectations par catégories d'âge

    In [ ]:
    Copied!
    merged_df_catage["Total"] = merged_df_catage["% affec région"]+ merged_df_catage["% affec projet"]+ merged_df_catage["% affec non-dédié"]
    merged_df_catage.round() 
    
    merged_df_catage["Total"] = merged_df_catage["% affec région"]+ merged_df_catage["% affec projet"]+ merged_df_catage["% affec non-dédié"] merged_df_catage.round()
    Out[ ]:
    % affec région % affec projet % affec non-dédié Total
    catégories âge
    0-25 ans 33.0 34.0 32.0 100.0
    25-40 ans 33.0 35.0 32.0 100.0
    40-60 ans 33.0 36.0 32.0 100.0
    60 ans et plus 33.0 34.0 33.0 100.0
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Part moyenne des affectations  par catégories d'ancienneté</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Part moyenne des affectations par catégories d'ancienneté

    "))

    Part moyenne des affectations par catégories d'ancienneté

    In [ ]:
    Copied!
    merged_df_ancienneté["Total"] = merged_df_ancienneté["% affec région"]+ merged_df_ancienneté["% affec projet"]+ merged_df_ancienneté["% affec non-dédié"]
    ordre_categories_ancienneté = ['Nouvel actionnaire depuis 2017 ou plus', 'Nouvel actionnaire entre 2012 à 2017', 'Nouvel actionnaire en 2012 ou moins']
    merged_df_ancienneté.reindex(ordre_categories_ancienneté)
    merged_df_ancienneté.round()
    
    merged_df_ancienneté["Total"] = merged_df_ancienneté["% affec région"]+ merged_df_ancienneté["% affec projet"]+ merged_df_ancienneté["% affec non-dédié"] ordre_categories_ancienneté = ['Nouvel actionnaire depuis 2017 ou plus', 'Nouvel actionnaire entre 2012 à 2017', 'Nouvel actionnaire en 2012 ou moins'] merged_df_ancienneté.reindex(ordre_categories_ancienneté) merged_df_ancienneté.round()
    Out[ ]:
    % affec région % affec projet % affec non-dédié Total
    ancienneté actionnaires
    Nouvel actionnaire depuis 2017 ou plus 33.0 35.0 32.0 100.0
    Nouvel actionnaire en 2012 ou moins 33.0 35.0 32.0 100.0
    Nouvel actionnaire entre 2012 à 2017 33.0 34.0 33.0 100.0
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Les actionnaires arrivés entre 2012 et 2017 affectaient  d'autant plus leurs souscriptions à des fermes</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Les actionnaires arrivés entre 2012 et 2017 affectaient d'autant plus leurs souscriptions à des fermes

    "))

    Les actionnaires arrivés entre 2012 et 2017 affectaient d'autant plus leurs souscriptions à des fermes

    In [ ]:
    Copied!
    merged_df_MC["Total"] = merged_df_MC["% affec région"]+ merged_df_MC["% affec projet"]+ merged_df_MC["% affec non-dédié"]
    merged_df_MC.round()
    
    merged_df_MC["Total"] = merged_df_MC["% affec région"]+ merged_df_MC["% affec projet"]+ merged_df_MC["% affec non-dédié"] merged_df_MC.round()
    Out[ ]:
    % affec région % affec projet % affec non-dédié Total
    multi-casquette ?
    Actionnaire uniquement 34.0 34.0 32.0 100.0
    Actionnaire-adhérent 33.0 35.0 32.0 100.0
    Actionnaire-donateur 33.0 34.0 33.0 100.0
    Triple-engagement 32.0 35.0 33.0 100.0
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Les actionnaires-adhérents ont tendance à plus affecter leurs souscriptions à des fermes ou à une région</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Les actionnaires-adhérents ont tendance à plus affecter leurs souscriptions à des fermes ou à une région

    "))

    Les actionnaires-adhérents ont tendance à plus affecter leurs souscriptions à des fermes ou à une région

    In [ ]:
    Copied!
    from IPython.display import display, HTML
    display(HTML("<div style='page-break-before: always;'></div>"))
    
    # Afficher un titre centré avec une taille de police plus grande
    display(HTML('<center><h2><u>Durée moyenne de reprise de souscriptions (on ne parle que de multi-souscripteurs)</u></h2></center>'))
    
    from IPython.display import display, HTML display(HTML("
    ")) # Afficher un titre centré avec une taille de police plus grande display(HTML('

    Durée moyenne de reprise de souscriptions (on ne parle que de multi-souscripteurs)

    '))

    Durée moyenne de reprise de souscriptions (on ne parle que de multi-souscripteurs)

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Il s'agit de regarder la durée entre différentes dates de prise de souscriptions par personne. On fait ensuite une moyenne individuelle de ces durées</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Il s'agit de regarder la durée entre différentes dates de prise de souscriptions par personne. On fait ensuite une moyenne individuelle de ces durées

    "))

    Il s'agit de regarder la durée entre différentes dates de prise de souscriptions par personne. On fait ensuite une moyenne individuelle de ces durées

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Durée moyenne de reprise de souscriptions pour actionnaires et ex actionnaires</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Durée moyenne de reprise de souscriptions pour actionnaires et ex actionnaires

    "))

    Durée moyenne de reprise de souscriptions pour actionnaires et ex actionnaires

    In [ ]:
    Copied!
    import pandas as pd
    import numpy as np
    
    columns_to_drop = ['âge', 'Territoire Terre de Liens', 'adhérent N', 'Donateur N',
                       'RFM-Date Première Souscription', 'Foncière : Capital possédé',
                       'Foncière : Nombre d\'actions détenues', 'Foncière : Part du capital possédée (%)',
                       'Numéro du contrat', 'Type d\'enregistrement des contrats', 'Nombre d\'actions à l\'acquisition',
                       'A fait l\'objet d\'un reçu fiscal', 'Affectation', 'Mouvement de titre Name', 'Nature du mouvement',
                       "Date d'activation", 'Actions - Date de fin', 'Nombre d\'actions échangées', 'Difference début fin',
                       'retrait complet ou partiel', 'année rachat', 'durée conservation', 'répartition année',
                       'catégories âge', 'ancienneté actionnaires', 'répartition année nouveau actionnaire',
                       'catégorie souscription', 'Type affectation', 'Nombre de souscriptions',"Affectation_dédié projet", "Affectation_dédié région","Affectation_non dédié "]
    
    df2_copy = df2.drop(columns=columns_to_drop).copy()
    
    df2_copy["Date d'activation"] = pd.to_datetime(df2_copy['Date du Mouvement'], format="%Y-%d-%m", dayfirst=True)
    
    # Trier le dataframe par nom et date
    df_sorted = df2_copy.sort_values(by=['ID du contact', 'Date du Mouvement'])
    
    # Calculer la différence de dates
    df_sorted['Différence'] = df_sorted.groupby('ID du contact')['Date du Mouvement'].diff()
    
    # Calculer la différence moyenne par nom, en excluant les valeurs manquantes
    df_diff_mean = df_sorted.groupby('ID du contact')['Différence'].mean().dropna().reset_index()
    
    
    # Convertir la colonne Différence en timedelta
    df_diff_mean['Différence'] = pd.to_timedelta(df_diff_mean['Différence'])
    
    df_diff_mean['Différence'] = df_diff_mean['Différence'].dt.floor('D')
    
    # Calculer la moyenne en durée d'année en ignorant les jours, heures, minutes et secondes
    mean_difference = np.mean(df_diff_mean['Différence'] / np.timedelta64(1, 'W'))
    mean_difference = mean_difference/ 52
    # Arrondir le résultat au dixième
    mean_difference_rounded = round(mean_difference, 1)
    
    # Afficher la moyenne en durée d'année arrondie
    print("Durée moyenne pour reprise d'actions pour actionnaires et ex actionnaires:", mean_difference_rounded)
    
    import pandas as pd import numpy as np columns_to_drop = ['âge', 'Territoire Terre de Liens', 'adhérent N', 'Donateur N', 'RFM-Date Première Souscription', 'Foncière : Capital possédé', 'Foncière : Nombre d\'actions détenues', 'Foncière : Part du capital possédée (%)', 'Numéro du contrat', 'Type d\'enregistrement des contrats', 'Nombre d\'actions à l\'acquisition', 'A fait l\'objet d\'un reçu fiscal', 'Affectation', 'Mouvement de titre Name', 'Nature du mouvement', "Date d'activation", 'Actions - Date de fin', 'Nombre d\'actions échangées', 'Difference début fin', 'retrait complet ou partiel', 'année rachat', 'durée conservation', 'répartition année', 'catégories âge', 'ancienneté actionnaires', 'répartition année nouveau actionnaire', 'catégorie souscription', 'Type affectation', 'Nombre de souscriptions',"Affectation_dédié projet", "Affectation_dédié région","Affectation_non dédié "] df2_copy = df2.drop(columns=columns_to_drop).copy() df2_copy["Date d'activation"] = pd.to_datetime(df2_copy['Date du Mouvement'], format="%Y-%d-%m", dayfirst=True) # Trier le dataframe par nom et date df_sorted = df2_copy.sort_values(by=['ID du contact', 'Date du Mouvement']) # Calculer la différence de dates df_sorted['Différence'] = df_sorted.groupby('ID du contact')['Date du Mouvement'].diff() # Calculer la différence moyenne par nom, en excluant les valeurs manquantes df_diff_mean = df_sorted.groupby('ID du contact')['Différence'].mean().dropna().reset_index() # Convertir la colonne Différence en timedelta df_diff_mean['Différence'] = pd.to_timedelta(df_diff_mean['Différence']) df_diff_mean['Différence'] = df_diff_mean['Différence'].dt.floor('D') # Calculer la moyenne en durée d'année en ignorant les jours, heures, minutes et secondes mean_difference = np.mean(df_diff_mean['Différence'] / np.timedelta64(1, 'W')) mean_difference = mean_difference/ 52 # Arrondir le résultat au dixième mean_difference_rounded = round(mean_difference, 1) # Afficher la moyenne en durée d'année arrondie print("Durée moyenne pour reprise d'actions pour actionnaires et ex actionnaires:", mean_difference_rounded)
    Durée moyenne pour reprise d'actions pour actionnaires et ex actionnaires: 2.8
    
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Clé de lecture : les souscripteurs qui ont au minimum 2 souscriptions en ont repris une en moyenne au bout de 2,4 ans</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Clé de lecture : les souscripteurs qui ont au minimum 2 souscriptions en ont repris une en moyenne au bout de 2,4 ans

    "))

    Clé de lecture : les souscripteurs qui ont au minimum 2 souscriptions en ont repris une en moyenne au bout de 2,4 ans

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Durée moyenne de reprise de souscriptions pour actionnaires</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Durée moyenne de reprise de souscriptions pour actionnaires

    "))

    Durée moyenne de reprise de souscriptions pour actionnaires

    In [ ]:
    Copied!
    df_actionnaire= df2_copy[df2_copy['Actionnaire ?'] == 1 ].copy()
    
    df_actionnaire= df2_copy[df2_copy['Actionnaire ?'] == 1 ].copy()
    In [ ]:
    Copied!
    df_actionnaire["Date d'activation"] = pd.to_datetime(df_actionnaire['Date du Mouvement'], dayfirst=True)
    
    # Trier le dataframe par nom et date
    df_sorted2 = df_actionnaire.sort_values(by=['ID du contact', 'Date du Mouvement'])
    
    # Calculer la différence de dates
    df_sorted2['Différence'] = df_sorted2.groupby('ID du contact')['Date du Mouvement'].diff()
    
    # Calculer la différence moyenne par nom, en excluant les valeurs manquantes
    df_diff_mean2 = df_sorted2.groupby('ID du contact')['Différence'].mean().dropna().reset_index()
    
    
    # Convertir la colonne Différence en timedelta
    df_diff_mean2['Différence'] = pd.to_timedelta(df_diff_mean2['Différence'])
    
    df_diff_mean2['Différence'] = df_diff_mean2['Différence'].dt.floor('D')
    
    # Calculer la moyenne en durée d'année en ignorant les jours, heures, minutes et secondes
    mean_difference2 = np.mean(df_diff_mean2['Différence'] / np.timedelta64(1, 'W'))
    mean_difference2 = mean_difference2/ 52 
    
    # Arrondir le résultat au dixième
    mean_difference_rounded2 = round(mean_difference2, 1)
    
    # Afficher la moyenne en durée d'année arrondie
    print("Durée moyenne pour reprise d'action pour actionnaires:", mean_difference_rounded2)
    
    df_actionnaire["Date d'activation"] = pd.to_datetime(df_actionnaire['Date du Mouvement'], dayfirst=True) # Trier le dataframe par nom et date df_sorted2 = df_actionnaire.sort_values(by=['ID du contact', 'Date du Mouvement']) # Calculer la différence de dates df_sorted2['Différence'] = df_sorted2.groupby('ID du contact')['Date du Mouvement'].diff() # Calculer la différence moyenne par nom, en excluant les valeurs manquantes df_diff_mean2 = df_sorted2.groupby('ID du contact')['Différence'].mean().dropna().reset_index() # Convertir la colonne Différence en timedelta df_diff_mean2['Différence'] = pd.to_timedelta(df_diff_mean2['Différence']) df_diff_mean2['Différence'] = df_diff_mean2['Différence'].dt.floor('D') # Calculer la moyenne en durée d'année en ignorant les jours, heures, minutes et secondes mean_difference2 = np.mean(df_diff_mean2['Différence'] / np.timedelta64(1, 'W')) mean_difference2 = mean_difference2/ 52 # Arrondir le résultat au dixième mean_difference_rounded2 = round(mean_difference2, 1) # Afficher la moyenne en durée d'année arrondie print("Durée moyenne pour reprise d'action pour actionnaires:", mean_difference_rounded2)
    Durée moyenne pour reprise d'action pour actionnaires: 2.8
    
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Durée moyenne de reprise de souscriptions pour multi-casquettes ? </h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Durée moyenne de reprise de souscriptions pour multi-casquettes ?

    "))

    Durée moyenne de reprise de souscriptions pour multi-casquettes ?

    In [ ]:
    Copied!
    df2.loc[:, "multi-casquette ?"] = df2.apply(lambda row: "Actionnaire-donateur" if row["Actionnaire ?"] == 1 and (row["Donateur N"] == 1 or row['RFM-Date Dernier Don'] >= twenty4_months_ago)  and row["adhérent N"] == 0 and row['adhérent N-1'] == 0
                                                else "Actionnaire-adhérent" if row["Actionnaire ?"] == 1 and (row["adhérent N"] == 1 or row['adhérent N-1'] == 1) and row["Donateur N"] == 0 and row['RFM-Date Dernier Don'] < twenty4_months_ago
                                                else "Triple-engagement" if row["Actionnaire ?"] == 1 and (row["adhérent N"] == 1 or row['adhérent N-1'] == 1) and (row["Donateur N"] == 1 or row['RFM-Date Dernier Don'] >= twenty4_months_ago)
                                                else "Actionnaire uniquement", axis=1)
    
    df_diff_mean3 = df_diff_mean2.merge(df2[['ID du contact', 'multi-casquette ?']], on='ID du contact', how='left')
    
    df_diff_mean3 = df_diff_mean3.drop_duplicates(subset="ID du contact")
    # Convertir la colonne Différence en timedelta
    df_diff_mean3['Différence'] = pd.to_timedelta(df_diff_mean3['Différence'])
    # Grouper le DataFrame d'origine par 'multi-casquette ?' et compter les occurrences
    count_per_category = df_diff_mean3.groupby('multi-casquette ?').size().reset_index(name='Nombre de personnes')
    df_diff_mean3['Différence'] = df_diff_mean3['Différence'].dt.floor('D')
    df_mean_diff = df_diff_mean3.groupby('multi-casquette ?')['Différence'].mean().reset_index()
    df_mean_diff['Différence en années'] = df_mean_diff['Différence'] / pd.Timedelta(days=365)
    df_mean_diff['Différence en années'] = df_mean_diff['Différence en années'].round(1)
    df_mean_diff = df_mean_diff.drop('Différence', axis=1)
    df_mean_diff = df_mean_diff.merge(count_per_category, on='multi-casquette ?', how='left')
    df_mean_diff
    
    df2.loc[:, "multi-casquette ?"] = df2.apply(lambda row: "Actionnaire-donateur" if row["Actionnaire ?"] == 1 and (row["Donateur N"] == 1 or row['RFM-Date Dernier Don'] >= twenty4_months_ago) and row["adhérent N"] == 0 and row['adhérent N-1'] == 0 else "Actionnaire-adhérent" if row["Actionnaire ?"] == 1 and (row["adhérent N"] == 1 or row['adhérent N-1'] == 1) and row["Donateur N"] == 0 and row['RFM-Date Dernier Don'] < twenty4_months_ago else "Triple-engagement" if row["Actionnaire ?"] == 1 and (row["adhérent N"] == 1 or row['adhérent N-1'] == 1) and (row["Donateur N"] == 1 or row['RFM-Date Dernier Don'] >= twenty4_months_ago) else "Actionnaire uniquement", axis=1) df_diff_mean3 = df_diff_mean2.merge(df2[['ID du contact', 'multi-casquette ?']], on='ID du contact', how='left') df_diff_mean3 = df_diff_mean3.drop_duplicates(subset="ID du contact") # Convertir la colonne Différence en timedelta df_diff_mean3['Différence'] = pd.to_timedelta(df_diff_mean3['Différence']) # Grouper le DataFrame d'origine par 'multi-casquette ?' et compter les occurrences count_per_category = df_diff_mean3.groupby('multi-casquette ?').size().reset_index(name='Nombre de personnes') df_diff_mean3['Différence'] = df_diff_mean3['Différence'].dt.floor('D') df_mean_diff = df_diff_mean3.groupby('multi-casquette ?')['Différence'].mean().reset_index() df_mean_diff['Différence en années'] = df_mean_diff['Différence'] / pd.Timedelta(days=365) df_mean_diff['Différence en années'] = df_mean_diff['Différence en années'].round(1) df_mean_diff = df_mean_diff.drop('Différence', axis=1) df_mean_diff = df_mean_diff.merge(count_per_category, on='multi-casquette ?', how='left') df_mean_diff
    Out[ ]:
    multi-casquette ? Différence en années Nombre de personnes
    0 Actionnaire uniquement 2.8 377
    1 Actionnaire-adhérent 2.9 1245
    2 Actionnaire-donateur 2.9 523
    3 Triple-engagement 2.7 1369
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Durée moyenne de reprise de souscriptions par catégories d'âge?  </h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Durée moyenne de reprise de souscriptions par catégories d'âge?

    "))

    Durée moyenne de reprise de souscriptions par catégories d'âge?

    In [ ]:
    Copied!
    df_diff_mean4 = df_diff_mean2.merge(df2[['ID du contact', 'catégories âge']], on='ID du contact', how='left')
    
    df_diff_mean4 = df_diff_mean4.drop_duplicates(subset="ID du contact")
    # Convertir la colonne Différence en timedelta
    df_diff_mean4['Différence'] = pd.to_timedelta(df_diff_mean4['Différence'])
    df_diff_mean4['Différence'] = df_diff_mean4['Différence'].dt.floor('D')
    count_per_category = df_diff_mean4.groupby('catégories âge').size().reset_index(name='Nombre de personnes')
    df_mean_diff2 = df_diff_mean4.groupby('catégories âge')['Différence'].mean().reset_index()
    df_mean_diff2['Différence en années'] = df_mean_diff2['Différence'] / pd.Timedelta(days=365)
    df_mean_diff2['Différence en années'] = df_mean_diff2['Différence en années'].round(1)
    df_mean_diff2 = df_mean_diff2.drop('Différence', axis=1)
    df_mean_diff2 = df_mean_diff2.merge(count_per_category, on='catégories âge', how='left')
    df_mean_diff2
    
    df_diff_mean4 = df_diff_mean2.merge(df2[['ID du contact', 'catégories âge']], on='ID du contact', how='left') df_diff_mean4 = df_diff_mean4.drop_duplicates(subset="ID du contact") # Convertir la colonne Différence en timedelta df_diff_mean4['Différence'] = pd.to_timedelta(df_diff_mean4['Différence']) df_diff_mean4['Différence'] = df_diff_mean4['Différence'].dt.floor('D') count_per_category = df_diff_mean4.groupby('catégories âge').size().reset_index(name='Nombre de personnes') df_mean_diff2 = df_diff_mean4.groupby('catégories âge')['Différence'].mean().reset_index() df_mean_diff2['Différence en années'] = df_mean_diff2['Différence'] / pd.Timedelta(days=365) df_mean_diff2['Différence en années'] = df_mean_diff2['Différence en années'].round(1) df_mean_diff2 = df_mean_diff2.drop('Différence', axis=1) df_mean_diff2 = df_mean_diff2.merge(count_per_category, on='catégories âge', how='left') df_mean_diff2
    Out[ ]:
    catégories âge Différence en années Nombre de personnes
    0 0-25 ans 2.8 957
    1 25-40 ans 2.7 590
    2 40-60 ans 2.9 761
    3 60 ans et plus 2.8 1206
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Durée moyenne de reprise de souscriptions par catégories d'ancienneté </h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Durée moyenne de reprise de souscriptions par catégories d'ancienneté

    "))

    Durée moyenne de reprise de souscriptions par catégories d'ancienneté

    In [ ]:
    Copied!
    df_diff_mean5 = df_diff_mean2.merge(df2[['ID du contact', 'ancienneté actionnaires']], on='ID du contact', how='left')
    
    df_diff_mean5 = df_diff_mean5.drop_duplicates(subset="ID du contact")
    # Convertir la colonne Différence en timedelta
    df_diff_mean5['Différence'] = pd.to_timedelta(df_diff_mean5['Différence'])
    df_diff_mean5['Différence'] = df_diff_mean5['Différence'].dt.floor('D')
    count_per_category = df_diff_mean5.groupby('ancienneté actionnaires').size().reset_index(name='Nombre de personnes')
    df_mean_diff3 = df_diff_mean5.groupby('ancienneté actionnaires')['Différence'].mean().reset_index()
    df_mean_diff3['Différence en années'] = df_mean_diff3['Différence'] / pd.Timedelta(days=365)
    df_mean_diff3['Différence en années'] = df_mean_diff3['Différence en années'].round(1)
    df_mean_diff3 = df_mean_diff3.drop('Différence', axis=1)
    # Ajouter une colonne pour définir l'ordre souhaité
    df_mean_diff3['ordre'] = df_mean_diff3['ancienneté actionnaires'].apply(lambda x: ordre_categories_ancienneté.index(x))
    df_mean_diff3 = df_mean_diff3.sort_values('ordre')
    # Supprimer la colonne "ordre"
    df_mean_diff3 = df_mean_diff3.drop('ordre', axis=1)
    df_mean_diff3 = df_mean_diff3.merge(count_per_category, on='ancienneté actionnaires', how='left')
    df_mean_diff3
    
    df_diff_mean5 = df_diff_mean2.merge(df2[['ID du contact', 'ancienneté actionnaires']], on='ID du contact', how='left') df_diff_mean5 = df_diff_mean5.drop_duplicates(subset="ID du contact") # Convertir la colonne Différence en timedelta df_diff_mean5['Différence'] = pd.to_timedelta(df_diff_mean5['Différence']) df_diff_mean5['Différence'] = df_diff_mean5['Différence'].dt.floor('D') count_per_category = df_diff_mean5.groupby('ancienneté actionnaires').size().reset_index(name='Nombre de personnes') df_mean_diff3 = df_diff_mean5.groupby('ancienneté actionnaires')['Différence'].mean().reset_index() df_mean_diff3['Différence en années'] = df_mean_diff3['Différence'] / pd.Timedelta(days=365) df_mean_diff3['Différence en années'] = df_mean_diff3['Différence en années'].round(1) df_mean_diff3 = df_mean_diff3.drop('Différence', axis=1) # Ajouter une colonne pour définir l'ordre souhaité df_mean_diff3['ordre'] = df_mean_diff3['ancienneté actionnaires'].apply(lambda x: ordre_categories_ancienneté.index(x)) df_mean_diff3 = df_mean_diff3.sort_values('ordre') # Supprimer la colonne "ordre" df_mean_diff3 = df_mean_diff3.drop('ordre', axis=1) df_mean_diff3 = df_mean_diff3.merge(count_per_category, on='ancienneté actionnaires', how='left') df_mean_diff3
    Out[ ]:
    ancienneté actionnaires Différence en années Nombre de personnes
    0 Nouvel actionnaire depuis 2017 ou plus 1.1 1191
    1 Nouvel actionnaire entre 2012 à 2017 2.7 1102
    2 Nouvel actionnaire en 2012 ou moins 4.5 1221
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Les actionnaires arrivés depuis 2017 reprennent plus régulièrement des souscriptions</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Les actionnaires arrivés depuis 2017 reprennent plus régulièrement des souscriptions

    "))

    Les actionnaires arrivés depuis 2017 reprennent plus régulièrement des souscriptions

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Durée moyenne de reprise de souscriptions par catégories de souscripteurs </h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Durée moyenne de reprise de souscriptions par catégories de souscripteurs

    "))

    Durée moyenne de reprise de souscriptions par catégories de souscripteurs

    In [ ]:
    Copied!
    df_diff_mean6 = df_diff_mean2.merge(df_MS[['ID du contact', 'Catégories souscripteurs']], on='ID du contact', how='left')
    
    df_diff_mean6 = df_diff_mean6.drop_duplicates(subset="ID du contact")
    # Convertir la colonne Différence en timedelta
    df_diff_mean6['Différence'] = pd.to_timedelta(df_diff_mean6['Différence'])
    df_diff_mean6['Différence'] = df_diff_mean6['Différence'].dt.floor('D')
    
    count_per_category = df_diff_mean6.groupby('Catégories souscripteurs').size().reset_index(name='Nombre de personnes')
    
    df_mean_diff4 = df_diff_mean6.groupby('Catégories souscripteurs')['Différence'].mean().reset_index()
    df_mean_diff4['Différence en années'] = df_mean_diff4['Différence'] / pd.Timedelta(days=365)
    df_mean_diff4['Différence en années'] = df_mean_diff4['Différence en années'].round(1)
    df_mean_diff4 = df_mean_diff4.drop('Différence', axis=1)
    # Ordre des catégories souhaitées
    ordre_categories_souscripteurs2 = ['2 souscriptions', '3 à 5 souscriptions', '6 à 10 souscriptions', '10 souscriptions et plus']
    
    # Ajouter une colonne pour définir l'ordre souhaité
    df_mean_diff4['ordre'] = df_mean_diff4['Catégories souscripteurs'].apply(lambda x: ordre_categories_souscripteurs2.index(x))
    
    # Trier le DataFrame en fonction de la colonne "ordre"
    df_mean_diff4 = df_mean_diff4.sort_values('ordre')
    
    # Supprimer la colonne "ordre"
    df_mean_diff4 = df_mean_diff4.drop('ordre', axis=1)
    
    # Réinitialiser les index
    df_mean_diff4.reset_index(drop=True, inplace=True)
    df_mean_diff4 = df_mean_diff4.merge(count_per_category, on='Catégories souscripteurs', how='left')
    
    
    df_mean_diff4
    
    df_diff_mean6 = df_diff_mean2.merge(df_MS[['ID du contact', 'Catégories souscripteurs']], on='ID du contact', how='left') df_diff_mean6 = df_diff_mean6.drop_duplicates(subset="ID du contact") # Convertir la colonne Différence en timedelta df_diff_mean6['Différence'] = pd.to_timedelta(df_diff_mean6['Différence']) df_diff_mean6['Différence'] = df_diff_mean6['Différence'].dt.floor('D') count_per_category = df_diff_mean6.groupby('Catégories souscripteurs').size().reset_index(name='Nombre de personnes') df_mean_diff4 = df_diff_mean6.groupby('Catégories souscripteurs')['Différence'].mean().reset_index() df_mean_diff4['Différence en années'] = df_mean_diff4['Différence'] / pd.Timedelta(days=365) df_mean_diff4['Différence en années'] = df_mean_diff4['Différence en années'].round(1) df_mean_diff4 = df_mean_diff4.drop('Différence', axis=1) # Ordre des catégories souhaitées ordre_categories_souscripteurs2 = ['2 souscriptions', '3 à 5 souscriptions', '6 à 10 souscriptions', '10 souscriptions et plus'] # Ajouter une colonne pour définir l'ordre souhaité df_mean_diff4['ordre'] = df_mean_diff4['Catégories souscripteurs'].apply(lambda x: ordre_categories_souscripteurs2.index(x)) # Trier le DataFrame en fonction de la colonne "ordre" df_mean_diff4 = df_mean_diff4.sort_values('ordre') # Supprimer la colonne "ordre" df_mean_diff4 = df_mean_diff4.drop('ordre', axis=1) # Réinitialiser les index df_mean_diff4.reset_index(drop=True, inplace=True) df_mean_diff4 = df_mean_diff4.merge(count_per_category, on='Catégories souscripteurs', how='left') df_mean_diff4
    Out[ ]:
    Catégories souscripteurs Différence en années Nombre de personnes
    0 2 souscriptions 3.1 2370
    1 3 à 5 souscriptions 2.2 1050
    2 6 à 10 souscriptions 1.0 73
    3 10 souscriptions et plus 0.8 21
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Les gros souscripteurs reprennent plus régulièrement des souscriptions</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Les gros souscripteurs reprennent plus régulièrement des souscriptions

    "))

    Les gros souscripteurs reprennent plus régulièrement des souscriptions

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h2>Notions : pour lecture des boites à moustaches ou box plots </h2>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Notions : pour lecture des boites à moustaches ou box plots

    "))

    Notions : pour lecture des boites à moustaches ou box plots

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Médiane = sépare la série de valeur en 2 parties. 50 % des valeurs sont au-dessous de la médiane et 50 % sont au dessus </h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Médiane = sépare la série de valeur en 2 parties. 50 % des valeurs sont au-dessous de la médiane et 50 % sont au dessus

    "))

    Médiane = sépare la série de valeur en 2 parties. 50 % des valeurs sont au-dessous de la médiane et 50 % sont au dessus

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Premier quartile (Q1) = 25 % des plus petites valeurs de la série sont compris avant cette valeur</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Premier quartile (Q1) = 25 % des plus petites valeurs de la série sont compris avant cette valeur

    "))

    Premier quartile (Q1) = 25 % des plus petites valeurs de la série sont compris avant cette valeur

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Troisième quartile (Q3)= 25 % des plus grandes valeurs de la série sont compris apres cette valeur soit 75 % des valeurs sont plus petite que cette valeur</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Troisième quartile (Q3)= 25 % des plus grandes valeurs de la série sont compris apres cette valeur soit 75 % des valeurs sont plus petite que cette valeur

    "))

    Troisième quartile (Q3)= 25 % des plus grandes valeurs de la série sont compris apres cette valeur soit 75 % des valeurs sont plus petite que cette valeur

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Les whiskers ou les bornes extremes des boites à moustaches correspondent au Q1 - 1,5*(Q3-Q1) pour la borne inférieure et  au Q3 + 1,5*(Q3-Q1) pour la borne supérieure. Si le max et le min sont inclus dans ces bornes alors se sont leurs valeurs qui seront représentées par les extrémités de la boite. S'ils existent des valeurs hors de ces bornes de whiskers alors les bornes des boites à moustache représenteront les valeurs de ces whiskers.</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Les whiskers ou les bornes extremes des boites à moustaches correspondent au Q1 - 1,5*(Q3-Q1) pour la borne inférieure et au Q3 + 1,5*(Q3-Q1) pour la borne supérieure. Si le max et le min sont inclus dans ces bornes alors se sont leurs valeurs qui seront représentées par les extrémités de la boite. S'ils existent des valeurs hors de ces bornes de whiskers alors les bornes des boites à moustache représenteront les valeurs de ces whiskers.

    "))

    Les whiskers ou les bornes extremes des boites à moustaches correspondent au Q1 - 1,5*(Q3-Q1) pour la borne inférieure et au Q3 + 1,5*(Q3-Q1) pour la borne supérieure. Si le max et le min sont inclus dans ces bornes alors se sont leurs valeurs qui seront représentées par les extrémités de la boite. S'ils existent des valeurs hors de ces bornes de whiskers alors les bornes des boites à moustache représenteront les valeurs de ces whiskers.

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Les valeurs hors des whiskers sont des valeurs aberrantes ou dites outliers. Ce sont les valeurs qui sont considérées comme extrèmes comparé au périmètre détermnié par la majorité des valeurs de la série</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Les valeurs hors des whiskers sont des valeurs aberrantes ou dites outliers. Ce sont les valeurs qui sont considérées comme extrèmes comparé au périmètre détermnié par la majorité des valeurs de la série

    "))

    Les valeurs hors des whiskers sont des valeurs aberrantes ou dites outliers. Ce sont les valeurs qui sont considérées comme extrèmes comparé au périmètre détermnié par la majorité des valeurs de la série

    In [ ]:
    Copied!
    import matplotlib.pyplot as plt
    import numpy as np
    df_diff_mean['Différence'] = df_diff_mean['Différence'].dt.total_seconds() / (365.25 * 24 * 60 * 60)
    df_diff_mean["Différence"] = df_diff_mean["Différence"].round(1)
    
    # Calculer la médiane, Q1 et Q3
    median = np.median(df_diff_mean['Différence'])
    q1 = np.percentile(df_diff_mean['Différence'], 25)
    q3 = np.percentile(df_diff_mean['Différence'], 75)
    
    # Calculer les limites inférieures et supérieures des whiskers
    iqr = q3 - q1
    lower_whisker = q1 - 1.5 * iqr
    upper_whisker = q3 + 1.5 * iqr
    upper_whisker = upper_whisker.round(1)
    # Créer le box plot horizontalement
    plt.figure(figsize=(8, 6))
    plt.boxplot(df_diff_mean['Différence'], vert=False)
    
    # Calculer le nombre d'outliers
    whiskers = plt.boxplot(df_diff_mean['Différence'], vert=False)['fliers']
    num_outliers = len(whiskers[0].get_data()[0])
    
    # Ajouter les valeurs de la médiane, Q1, Q3, limites des whiskers au graphique
    plt.text(0.02, 0.9, f"Médiane: {median}", transform=plt.gca().transAxes)
    plt.text(0.02, 0.8, f"Q1: {q1}", transform=plt.gca().transAxes)
    plt.text(0.02, 0.7, f"Q3: {q3}", transform=plt.gca().transAxes)
    plt.text(0.5, 0.8, f"Borne supérieur du boxplot: {upper_whisker}", transform=plt.gca().transAxes)
    plt.text(0.5, 0.9, f"Outliers: {num_outliers}", transform=plt.gca().transAxes)
    
    # Titre et étiquette de l'axe y
    plt.title("Box plot de la durée moyenne entre reprise de souscriptions pour ex-actionnaires et actionnaires actuels")
    plt.xlabel("Nombre d'années")
    plt.ylabel("")
    plt.yticks([])
    # Afficher le box plot
    plt.show()
    
    import matplotlib.pyplot as plt import numpy as np df_diff_mean['Différence'] = df_diff_mean['Différence'].dt.total_seconds() / (365.25 * 24 * 60 * 60) df_diff_mean["Différence"] = df_diff_mean["Différence"].round(1) # Calculer la médiane, Q1 et Q3 median = np.median(df_diff_mean['Différence']) q1 = np.percentile(df_diff_mean['Différence'], 25) q3 = np.percentile(df_diff_mean['Différence'], 75) # Calculer les limites inférieures et supérieures des whiskers iqr = q3 - q1 lower_whisker = q1 - 1.5 * iqr upper_whisker = q3 + 1.5 * iqr upper_whisker = upper_whisker.round(1) # Créer le box plot horizontalement plt.figure(figsize=(8, 6)) plt.boxplot(df_diff_mean['Différence'], vert=False) # Calculer le nombre d'outliers whiskers = plt.boxplot(df_diff_mean['Différence'], vert=False)['fliers'] num_outliers = len(whiskers[0].get_data()[0]) # Ajouter les valeurs de la médiane, Q1, Q3, limites des whiskers au graphique plt.text(0.02, 0.9, f"Médiane: {median}", transform=plt.gca().transAxes) plt.text(0.02, 0.8, f"Q1: {q1}", transform=plt.gca().transAxes) plt.text(0.02, 0.7, f"Q3: {q3}", transform=plt.gca().transAxes) plt.text(0.5, 0.8, f"Borne supérieur du boxplot: {upper_whisker}", transform=plt.gca().transAxes) plt.text(0.5, 0.9, f"Outliers: {num_outliers}", transform=plt.gca().transAxes) # Titre et étiquette de l'axe y plt.title("Box plot de la durée moyenne entre reprise de souscriptions pour ex-actionnaires et actionnaires actuels") plt.xlabel("Nombre d'années") plt.ylabel("") plt.yticks([]) # Afficher le box plot plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Clés de lecture : Il y a 50 % de tous les multi-souscripteurs qui ont repris une souscription au bout de 1,6 an ou moins. Il y a 25 % d'entre eux qui en ont repris une au bout d'un 1 an ou moins(Q1), 25 % en ont repris une au bout de 3 ans ou plus (Q3) soit 75 % qui en ont repris au bout de 3 ans ou moins.</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Clés de lecture : Il y a 50 % de tous les multi-souscripteurs qui ont repris une souscription au bout de 1,6 an ou moins. Il y a 25 % d'entre eux qui en ont repris une au bout d'un 1 an ou moins(Q1), 25 % en ont repris une au bout de 3 ans ou plus (Q3) soit 75 % qui en ont repris au bout de 3 ans ou moins.

    "))

    Clés de lecture : Il y a 50 % de tous les multi-souscripteurs qui ont repris une souscription au bout de 1,6 an ou moins. Il y a 25 % d'entre eux qui en ont repris une au bout d'un 1 an ou moins(Q1), 25 % en ont repris une au bout de 3 ans ou plus (Q3) soit 75 % qui en ont repris au bout de 3 ans ou moins.

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Il y a 472 personnes qui sont considérées comme ayant une durée de reprise de souscriptions jugée statistiquement ''hors normes'' car cette durée est 1,5 fois plus grande que celle de 75 % de souscripteurs</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Il y a 472 personnes qui sont considérées comme ayant une durée de reprise de souscriptions jugée statistiquement ''hors normes'' car cette durée est 1,5 fois plus grande que celle de 75 % de souscripteurs

    "))

    Il y a 472 personnes qui sont considérées comme ayant une durée de reprise de souscriptions jugée statistiquement ''hors normes'' car cette durée est 1,5 fois plus grande que celle de 75 % de souscripteurs

    In [ ]:
    Copied!
    import matplotlib.pyplot as plt
    import numpy as np
    df_diff_mean2['Différence'] = df_diff_mean2['Différence'].dt.total_seconds() / (365.25 * 24 * 60 * 60)
    df_diff_mean2["Différence"] = df_diff_mean2["Différence"].round(1)
    
    # Calculer la médiane, Q1 et Q3
    median = np.median(df_diff_mean2['Différence'])
    q1 = np.percentile(df_diff_mean2['Différence'], 25)
    q3 = np.percentile(df_diff_mean2['Différence'], 75)
    
    # Calculer les limites inférieures et supérieures des whiskers
    iqr = q3 - q1
    lower_whisker = q1 - 1.5 * iqr
    upper_whisker = q3 + 1.5 * iqr
    upper_whisker = upper_whisker.round(1)
    # Créer le box plot horizontalement
    plt.figure(figsize=(8, 6))
    plt.boxplot(df_diff_mean2['Différence'], vert=False)
    
    # Calculer le nombre d'outliers
    whiskers = plt.boxplot(df_diff_mean2['Différence'], vert=False)['fliers']
    num_outliers = len(whiskers[0].get_data()[0])
    
    # Ajouter les valeurs de la médiane, Q1, Q3, limites des whiskers au graphique
    plt.text(0.02, 0.9, f"Médiane: {median}", transform=plt.gca().transAxes)
    plt.text(0.02, 0.8, f"Q1: {q1}", transform=plt.gca().transAxes)
    plt.text(0.02, 0.7, f"Q3: {q3}", transform=plt.gca().transAxes)
    plt.text(0.5, 0.8, f"borne supérieur du boxplot: {upper_whisker}", transform=plt.gca().transAxes)
    plt.text(0.5, 0.9, f"Outliers: {num_outliers}", transform=plt.gca().transAxes)
    
    # Titre et étiquette de l'axe y
    plt.title("Box plot de la durée moyenne entre reprise de souscriptions pour les actionnaires actuels")
    plt.xlabel("Nombre d'années")
    plt.ylabel("")
    plt.yticks([])
    
    # Afficher le box plot
    plt.show()
    
    import matplotlib.pyplot as plt import numpy as np df_diff_mean2['Différence'] = df_diff_mean2['Différence'].dt.total_seconds() / (365.25 * 24 * 60 * 60) df_diff_mean2["Différence"] = df_diff_mean2["Différence"].round(1) # Calculer la médiane, Q1 et Q3 median = np.median(df_diff_mean2['Différence']) q1 = np.percentile(df_diff_mean2['Différence'], 25) q3 = np.percentile(df_diff_mean2['Différence'], 75) # Calculer les limites inférieures et supérieures des whiskers iqr = q3 - q1 lower_whisker = q1 - 1.5 * iqr upper_whisker = q3 + 1.5 * iqr upper_whisker = upper_whisker.round(1) # Créer le box plot horizontalement plt.figure(figsize=(8, 6)) plt.boxplot(df_diff_mean2['Différence'], vert=False) # Calculer le nombre d'outliers whiskers = plt.boxplot(df_diff_mean2['Différence'], vert=False)['fliers'] num_outliers = len(whiskers[0].get_data()[0]) # Ajouter les valeurs de la médiane, Q1, Q3, limites des whiskers au graphique plt.text(0.02, 0.9, f"Médiane: {median}", transform=plt.gca().transAxes) plt.text(0.02, 0.8, f"Q1: {q1}", transform=plt.gca().transAxes) plt.text(0.02, 0.7, f"Q3: {q3}", transform=plt.gca().transAxes) plt.text(0.5, 0.8, f"borne supérieur du boxplot: {upper_whisker}", transform=plt.gca().transAxes) plt.text(0.5, 0.9, f"Outliers: {num_outliers}", transform=plt.gca().transAxes) # Titre et étiquette de l'axe y plt.title("Box plot de la durée moyenne entre reprise de souscriptions pour les actionnaires actuels") plt.xlabel("Nombre d'années") plt.ylabel("") plt.yticks([]) # Afficher le box plot plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    import matplotlib.pyplot as plt
    import numpy as np
    
    # Convertir la colonne 'Différence' en années
    df_diff_mean3['Différence'] = df_diff_mean3['Différence'] / np.timedelta64(1, 'W')
    df_diff_mean3 = df_diff_mean3/ 52
    df_diff_mean3['Différence'] = df_diff_mean3['Différence'].round(1)
    # Créer les groupes pour le boxplot
    grouped_data = df_diff_mean3.groupby('multi-casquette ?')['Différence'].apply(list)
    
    # Créer le boxplot en inversant l'ordre des positions
    # Créer le boxplot
    plt.figure(figsize=(8, 6))
    boxes = plt.boxplot(grouped_data, vert=False, patch_artist=True)
    
    # Récupérer les étiquettes de catégories dans l'ordre personnalisé
    categories = grouped_data.index
    
    # Couleurs personnalisées pour chaque boîte
    custom_colors =  ['powderblue', 'lightskyblue', 'lightslategray', 'lightsteelblue', 'steelblue']
    
    # Attribution des couleurs aux boîtes et création de la légende
    for box, color, category in zip(boxes['boxes'], custom_colors, categories):
        box.set_facecolor(color)
        
    # Titre et étiquette des axes
    plt.title("Box plots de la durée moyenne entre reprise de souscriptions par catégories de multi-engagement")
    plt.xlabel("Nombre d'années")
    plt.ylabel("catégories de multi-engagement")
    plt.yticks([])
    
    # Création de la légende en utilisant des proxies (éléments de la légende sans affichage réel)
    legend_proxies = [plt.Rectangle((0, 0), 1, 1, color=color) for color in custom_colors]
    plt.legend(legend_proxies, categories)
    
    # Afficher le boxplot
    plt.show()
    
    import matplotlib.pyplot as plt import numpy as np # Convertir la colonne 'Différence' en années df_diff_mean3['Différence'] = df_diff_mean3['Différence'] / np.timedelta64(1, 'W') df_diff_mean3 = df_diff_mean3/ 52 df_diff_mean3['Différence'] = df_diff_mean3['Différence'].round(1) # Créer les groupes pour le boxplot grouped_data = df_diff_mean3.groupby('multi-casquette ?')['Différence'].apply(list) # Créer le boxplot en inversant l'ordre des positions # Créer le boxplot plt.figure(figsize=(8, 6)) boxes = plt.boxplot(grouped_data, vert=False, patch_artist=True) # Récupérer les étiquettes de catégories dans l'ordre personnalisé categories = grouped_data.index # Couleurs personnalisées pour chaque boîte custom_colors = ['powderblue', 'lightskyblue', 'lightslategray', 'lightsteelblue', 'steelblue'] # Attribution des couleurs aux boîtes et création de la légende for box, color, category in zip(boxes['boxes'], custom_colors, categories): box.set_facecolor(color) # Titre et étiquette des axes plt.title("Box plots de la durée moyenne entre reprise de souscriptions par catégories de multi-engagement") plt.xlabel("Nombre d'années") plt.ylabel("catégories de multi-engagement") plt.yticks([]) # Création de la légende en utilisant des proxies (éléments de la légende sans affichage réel) legend_proxies = [plt.Rectangle((0, 0), 1, 1, color=color) for color in custom_colors] plt.legend(legend_proxies, categories) # Afficher le boxplot plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    #Créer les groupes pour le boxplot
    grouped_data = df_diff_mean3.groupby('multi-casquette ?')['Différence'].apply(list)
    
    # Créer le tableau
    df_retrait_multicasquette = grouped_data.apply(lambda x: pd.Series({
        'Médiane Durée conservation': np.median(x),
        'Q1': np.percentile(x, 25),
        'Q3': np.percentile(x, 75),
        'Upper Whiskers': np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25)),
        "Nombre d'outliers": np.sum((x < np.percentile(x, 25) - 1.5*(np.percentile(x, 75) - np.percentile(x, 25))) | (x > np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25))))
    })).reset_index()
    df_retrait_multicasquette.rename(columns={'multi-casquette ?': 'catégories de multi-engagement'}, inplace=True)
    # Inverser l'ordre des indices dans le DataFrame
    df_retrait_multicasquette = df_retrait_multicasquette.iloc[::-1].reset_index(drop=True)
    df_retrait_multicasquette
    
    #Créer les groupes pour le boxplot grouped_data = df_diff_mean3.groupby('multi-casquette ?')['Différence'].apply(list) # Créer le tableau df_retrait_multicasquette = grouped_data.apply(lambda x: pd.Series({ 'Médiane Durée conservation': np.median(x), 'Q1': np.percentile(x, 25), 'Q3': np.percentile(x, 75), 'Upper Whiskers': np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25)), "Nombre d'outliers": np.sum((x < np.percentile(x, 25) - 1.5*(np.percentile(x, 75) - np.percentile(x, 25))) | (x > np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25)))) })).reset_index() df_retrait_multicasquette.rename(columns={'multi-casquette ?': 'catégories de multi-engagement'}, inplace=True) # Inverser l'ordre des indices dans le DataFrame df_retrait_multicasquette = df_retrait_multicasquette.iloc[::-1].reset_index(drop=True) df_retrait_multicasquette
    Out[ ]:
    catégories de multi-engagement Médiane Durée conservation Q1 Q3 Upper Whiskers Nombre d'outliers
    0 Triple-engagement 1.9 0.9 3.9 8.40 54.0
    1 Actionnaire-donateur 1.9 0.9 4.2 9.15 26.0
    2 Actionnaire-adhérent 2.0 0.9 3.9 8.40 80.0
    3 Actionnaire uniquement 1.8 0.8 3.7 8.05 24.0
    In [ ]:
    Copied!
    # Convertir la colonne 'Différence' en années
    df_diff_mean4['Différence'] = df_diff_mean4['Différence'] / np.timedelta64(1, 'W')
    df_diff_mean4 = df_diff_mean4/ 52 
    df_diff_mean4['Différence'] = df_diff_mean4['Différence'].round(1)
    # Créer les groupes pour le boxplot
    grouped_data = df_diff_mean4.groupby('catégories âge')['Différence'].apply(list)
    custom_order = ['60 ans et plus', '40-60 ans', '25-40 ans', '0-25 ans']
    
    # Réorganiser les indices du groupe grouped_data
    grouped_data = grouped_data.reindex(custom_order)
    
    # Créer le boxplot
    plt.figure(figsize=(8, 6))
    boxes = plt.boxplot(grouped_data, vert=False, patch_artist=True)
    
    # Récupérer les étiquettes de catégories dans l'ordre personnalisé
    categories = grouped_data.index
    
    # Couleurs personnalisées pour chaque boîte
    custom_colors =  ['powderblue', 'lightskyblue', 'lightslategray', 'lightsteelblue', 'steelblue']
    
    # Attribution des couleurs aux boîtes et création de la légende
    for box, color, category in zip(boxes['boxes'], custom_colors, categories):
        box.set_facecolor(color)
        
    # Titre et étiquette des axes
    plt.title("Box plots de la durée moyenne entre reprise de souscriptions par catégorie d'age")
    plt.xlabel("Nombre d'années")
    plt.ylabel("catégories âge")
    plt.yticks([])
    
    # Création de la légende en utilisant des proxies (éléments de la légende sans affichage réel)
    legend_proxies = [plt.Rectangle((0, 0), 1, 1, color=color) for color in custom_colors]
    plt.legend(legend_proxies, categories)
    
    # Afficher le boxplot
    plt.show()
    
    # Convertir la colonne 'Différence' en années df_diff_mean4['Différence'] = df_diff_mean4['Différence'] / np.timedelta64(1, 'W') df_diff_mean4 = df_diff_mean4/ 52 df_diff_mean4['Différence'] = df_diff_mean4['Différence'].round(1) # Créer les groupes pour le boxplot grouped_data = df_diff_mean4.groupby('catégories âge')['Différence'].apply(list) custom_order = ['60 ans et plus', '40-60 ans', '25-40 ans', '0-25 ans'] # Réorganiser les indices du groupe grouped_data grouped_data = grouped_data.reindex(custom_order) # Créer le boxplot plt.figure(figsize=(8, 6)) boxes = plt.boxplot(grouped_data, vert=False, patch_artist=True) # Récupérer les étiquettes de catégories dans l'ordre personnalisé categories = grouped_data.index # Couleurs personnalisées pour chaque boîte custom_colors = ['powderblue', 'lightskyblue', 'lightslategray', 'lightsteelblue', 'steelblue'] # Attribution des couleurs aux boîtes et création de la légende for box, color, category in zip(boxes['boxes'], custom_colors, categories): box.set_facecolor(color) # Titre et étiquette des axes plt.title("Box plots de la durée moyenne entre reprise de souscriptions par catégorie d'age") plt.xlabel("Nombre d'années") plt.ylabel("catégories âge") plt.yticks([]) # Création de la légende en utilisant des proxies (éléments de la légende sans affichage réel) legend_proxies = [plt.Rectangle((0, 0), 1, 1, color=color) for color in custom_colors] plt.legend(legend_proxies, categories) # Afficher le boxplot plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    custom_order = ['0-25 ans', '25-40 ans', '40-60 ans', '60 ans et plus']
    
    # Créer les groupes pour le boxplot
    grouped_data = df_diff_mean4.groupby('catégories âge')['Différence'].apply(list)
    grouped_data = grouped_data.reindex(custom_order)
    
    def calculate_outliers(x):
        return np.sum((x < np.percentile(x, 25) - 1.5*(np.percentile(x, 75) - np.percentile(x, 25))) | (x > np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25))))
    
    df_retraitageage = grouped_data.apply(lambda x: pd.Series({
        'Médiane Durée conservation': np.median(x),
        'Q1': np.percentile(x, 25),
        'Q3': np.percentile(x, 75),
        'Upper Whiskers': np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25)),
        'Nombre d\'outliers': calculate_outliers(x)
    })).reset_index()
    df_retraitageage.rename(columns={'catégories âge': 'catégories d\'âge'}, inplace=True)
    
    df_retraitageage
    
    custom_order = ['0-25 ans', '25-40 ans', '40-60 ans', '60 ans et plus'] # Créer les groupes pour le boxplot grouped_data = df_diff_mean4.groupby('catégories âge')['Différence'].apply(list) grouped_data = grouped_data.reindex(custom_order) def calculate_outliers(x): return np.sum((x < np.percentile(x, 25) - 1.5*(np.percentile(x, 75) - np.percentile(x, 25))) | (x > np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25)))) df_retraitageage = grouped_data.apply(lambda x: pd.Series({ 'Médiane Durée conservation': np.median(x), 'Q1': np.percentile(x, 25), 'Q3': np.percentile(x, 75), 'Upper Whiskers': np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25)), 'Nombre d\'outliers': calculate_outliers(x) })).reset_index() df_retraitageage.rename(columns={'catégories âge': 'catégories d\'âge'}, inplace=True) df_retraitageage
    Out[ ]:
    catégories d'âge Médiane Durée conservation Q1 Q3 Upper Whiskers Nombre d'outliers
    0 0-25 ans 1.9 0.9 3.8 8.15 54.0
    1 25-40 ans 1.8 0.8 3.8 8.30 29.0
    2 40-60 ans 2.0 0.9 3.9 8.40 49.0
    3 60 ans et plus 2.1 0.9 4.0 8.65 56.0
    In [ ]:
    Copied!
    # Convertir la colonne 'Différence' en années
    df_diff_mean5['Différence'] = df_diff_mean5['Différence'] / np.timedelta64(1, 'W')
    df_diff_mean5 = df_diff_mean5/ 52
    df_diff_mean5['Différence'] = df_diff_mean5['Différence'].round(1)
    ordre_categories_ancienneté = ['Nouvel actionnaire depuis 2017 ou plus', 'Nouvel actionnaire entre 2012 à 2017', 'Nouvel actionnaire en 2012 ou moins']
    
    # Créer les groupes pour le boxplot
    grouped_data = df_diff_mean5.groupby('ancienneté actionnaires')['Différence'].apply(list)
    grouped_data= grouped_data.reindex(ordre_categories_ancienneté)
    # Créer le boxplot en inversant l'ordre des positions
    # Créer le boxplot
    plt.figure(figsize=(8, 6))
    boxes = plt.boxplot(grouped_data, vert=False, patch_artist=True)
    
    # Récupérer les étiquettes de catégories dans l'ordre personnalisé
    categories = grouped_data.index
    # Couleurs personnalisées pour chaque boîte
    custom_colors =  ['powderblue', 'lightskyblue', 'lightslategray', 'lightsteelblue', 'steelblue']
    
    # Attribution des couleurs aux boîtes et création de la légende
    for box, color, category in zip(boxes['boxes'], custom_colors, categories):
        box.set_facecolor(color)
        
    # Titre et étiquette des axes
    plt.title("Box plots de la durée moyenne entre reprise de souscriptions par catégories d'ancienneté des actionnaires")
    plt.xlabel("Nombre d'années")
    plt.ylabel("Catégories d'ancienneté")
    plt.yticks([])
    
    # Création de la légende en utilisant des proxies (éléments de la légende sans affichage réel)
    legend_proxies = [plt.Rectangle((0, 0), 1, 1, color=color) for color in custom_colors]
    plt.legend(legend_proxies, categories)
    
    # Afficher le boxplot
    plt.show()
    
    # Convertir la colonne 'Différence' en années df_diff_mean5['Différence'] = df_diff_mean5['Différence'] / np.timedelta64(1, 'W') df_diff_mean5 = df_diff_mean5/ 52 df_diff_mean5['Différence'] = df_diff_mean5['Différence'].round(1) ordre_categories_ancienneté = ['Nouvel actionnaire depuis 2017 ou plus', 'Nouvel actionnaire entre 2012 à 2017', 'Nouvel actionnaire en 2012 ou moins'] # Créer les groupes pour le boxplot grouped_data = df_diff_mean5.groupby('ancienneté actionnaires')['Différence'].apply(list) grouped_data= grouped_data.reindex(ordre_categories_ancienneté) # Créer le boxplot en inversant l'ordre des positions # Créer le boxplot plt.figure(figsize=(8, 6)) boxes = plt.boxplot(grouped_data, vert=False, patch_artist=True) # Récupérer les étiquettes de catégories dans l'ordre personnalisé categories = grouped_data.index # Couleurs personnalisées pour chaque boîte custom_colors = ['powderblue', 'lightskyblue', 'lightslategray', 'lightsteelblue', 'steelblue'] # Attribution des couleurs aux boîtes et création de la légende for box, color, category in zip(boxes['boxes'], custom_colors, categories): box.set_facecolor(color) # Titre et étiquette des axes plt.title("Box plots de la durée moyenne entre reprise de souscriptions par catégories d'ancienneté des actionnaires") plt.xlabel("Nombre d'années") plt.ylabel("Catégories d'ancienneté") plt.yticks([]) # Création de la légende en utilisant des proxies (éléments de la légende sans affichage réel) legend_proxies = [plt.Rectangle((0, 0), 1, 1, color=color) for color in custom_colors] plt.legend(legend_proxies, categories) # Afficher le boxplot plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    import pandas as pd
    import numpy as np
    
    # Calculer le nombre de personnes par catégorie d'ancienneté
    df_retraitanciennetéactio = df_diff_mean5['ancienneté actionnaires'].value_counts().to_frame().reset_index()
    df_retraitanciennetéactio.columns = ['ancienneté actionnaires', "Nombre d'individus"]
    
    # Calculer la médiane, Q1, Q3 et les whiskers de la variable "Durée actionnariat" pour chaque catégorie
    ordre_categories_ancienneté = ['Nouvel actionnaire depuis 2017 ou plus', 'Nouvel actionnaire entre 2012 à 2017', 'Nouvel actionnaire en 2012 ou moins']
    df_stats = df_diff_mean5.groupby('ancienneté actionnaires')['Différence'].agg(['median', lambda x: np.percentile(x, 25), lambda x: np.percentile(x, 75), lambda x: np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25))]).reindex(ordre_categories_ancienneté).reset_index()
    df_stats.columns = ['ancienneté actionnaires', 'Médiane Durée conservation', 'Q1', 'Q3', 'Upper Whiskers']
    
    # Calculer le nombre d'outliers pour chaque catégorie
    df_outliers = df_diff_mean5.groupby('ancienneté actionnaires')['Différence'].apply(lambda x: np.sum((x < np.percentile(x, 25) - 1.5*(np.percentile(x, 75) - np.percentile(x, 25))) | (x > np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25))))).reindex(ordre_categories_ancienneté).reset_index()
    df_outliers.columns = ['ancienneté actionnaires', "Nombre d'outliers"]
    
    # Fusionner les DataFrames pour ajouter les statistiques et le nombre d'outliers
    df_retraitanciennetéactio = pd.merge(df_retraitanciennetéactio, df_stats, on='ancienneté actionnaires')
    df_retraitanciennetéactio= pd.merge(df_retraitanciennetéactio, df_outliers, on='ancienneté actionnaires')
    df_retraitanciennetéactio.rename(columns={'Médiane Durée conservation': 'Médiane'}, inplace=True)
    df_retraitanciennetéactio = df_retraitanciennetéactio.set_index('ancienneté actionnaires').reindex(ordre_categories_ancienneté).reset_index()
    df_retraitanciennetéactio
    
    import pandas as pd import numpy as np # Calculer le nombre de personnes par catégorie d'ancienneté df_retraitanciennetéactio = df_diff_mean5['ancienneté actionnaires'].value_counts().to_frame().reset_index() df_retraitanciennetéactio.columns = ['ancienneté actionnaires', "Nombre d'individus"] # Calculer la médiane, Q1, Q3 et les whiskers de la variable "Durée actionnariat" pour chaque catégorie ordre_categories_ancienneté = ['Nouvel actionnaire depuis 2017 ou plus', 'Nouvel actionnaire entre 2012 à 2017', 'Nouvel actionnaire en 2012 ou moins'] df_stats = df_diff_mean5.groupby('ancienneté actionnaires')['Différence'].agg(['median', lambda x: np.percentile(x, 25), lambda x: np.percentile(x, 75), lambda x: np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25))]).reindex(ordre_categories_ancienneté).reset_index() df_stats.columns = ['ancienneté actionnaires', 'Médiane Durée conservation', 'Q1', 'Q3', 'Upper Whiskers'] # Calculer le nombre d'outliers pour chaque catégorie df_outliers = df_diff_mean5.groupby('ancienneté actionnaires')['Différence'].apply(lambda x: np.sum((x < np.percentile(x, 25) - 1.5*(np.percentile(x, 75) - np.percentile(x, 25))) | (x > np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25))))).reindex(ordre_categories_ancienneté).reset_index() df_outliers.columns = ['ancienneté actionnaires', "Nombre d'outliers"] # Fusionner les DataFrames pour ajouter les statistiques et le nombre d'outliers df_retraitanciennetéactio = pd.merge(df_retraitanciennetéactio, df_stats, on='ancienneté actionnaires') df_retraitanciennetéactio= pd.merge(df_retraitanciennetéactio, df_outliers, on='ancienneté actionnaires') df_retraitanciennetéactio.rename(columns={'Médiane Durée conservation': 'Médiane'}, inplace=True) df_retraitanciennetéactio = df_retraitanciennetéactio.set_index('ancienneté actionnaires').reindex(ordre_categories_ancienneté).reset_index() df_retraitanciennetéactio
    Out[ ]:
    ancienneté actionnaires Nombre d'individus Médiane Q1 Q3 Upper Whiskers Nombre d'outliers
    0 Nouvel actionnaire depuis 2017 ou plus 1191 0.9 0.4 1.55 3.275 54
    1 Nouvel actionnaire entre 2012 à 2017 1102 2.3 1.2 3.70 7.450 31
    2 Nouvel actionnaire en 2012 ou moins 1221 3.9 2.0 6.30 12.750 20
    In [ ]:
    Copied!
    import numpy as np
    import matplotlib.pyplot as plt
    
    # Convertir la colonne 'Différence' en années
    df_diff_mean6['Différence'] = df_diff_mean6['Différence'] / np.timedelta64(1, 'W')
    df_diff_mean6 = df_diff_mean6/ 52
    df_diff_mean6['Différence'] = df_diff_mean6['Différence'].round(1)
    
    # Créer les groupes pour le boxplot et définir l'ordre souhaité
    custom_order = [ '2 souscriptions', '3 à 5 souscriptions', '6 à 10 souscriptions', '10 souscriptions et plus']
    grouped_data = df_diff_mean6.groupby('Catégories souscripteurs')['Différence'].apply(list)
    grouped_data = grouped_data.reindex(custom_order)
    
    # Inverser l'ordre des données groupées
    grouped_data = grouped_data[::-1]
    
    # Créer le boxplot
    plt.figure(figsize=(8, 6))
    boxes = plt.boxplot(grouped_data, vert=False, patch_artist=True)
    
    # Récupérer les étiquettes de catégories dans l'ordre personnalisé
    categories = grouped_data.index
    
    # Couleurs personnalisées pour chaque boîte
    custom_colors =  ['powderblue', 'lightskyblue', 'lightslategray', 'lightsteelblue', 'steelblue']
    
    # Attribution des couleurs aux boîtes et création de la légende
    for box, color, category in zip(boxes['boxes'], custom_colors, categories):
        box.set_facecolor(color)
    
    # Titre et étiquette des axes
    plt.title("Box plots de la durée moyenne entre reprise de souscriptions par catégories de souscripteurs")
    plt.xlabel("Nombre d'années")
    plt.ylabel("Catégories d'ancienneté")
    plt.yticks([])
    
    # Création de la légende en utilisant des proxies (éléments de la légende sans affichage réel)
    legend_proxies = [plt.Rectangle((0, 0), 1, 1, color=color) for color in custom_colors]
    plt.legend(legend_proxies, categories)
    
    # Afficher le boxplot
    plt.show()
    
    import numpy as np import matplotlib.pyplot as plt # Convertir la colonne 'Différence' en années df_diff_mean6['Différence'] = df_diff_mean6['Différence'] / np.timedelta64(1, 'W') df_diff_mean6 = df_diff_mean6/ 52 df_diff_mean6['Différence'] = df_diff_mean6['Différence'].round(1) # Créer les groupes pour le boxplot et définir l'ordre souhaité custom_order = [ '2 souscriptions', '3 à 5 souscriptions', '6 à 10 souscriptions', '10 souscriptions et plus'] grouped_data = df_diff_mean6.groupby('Catégories souscripteurs')['Différence'].apply(list) grouped_data = grouped_data.reindex(custom_order) # Inverser l'ordre des données groupées grouped_data = grouped_data[::-1] # Créer le boxplot plt.figure(figsize=(8, 6)) boxes = plt.boxplot(grouped_data, vert=False, patch_artist=True) # Récupérer les étiquettes de catégories dans l'ordre personnalisé categories = grouped_data.index # Couleurs personnalisées pour chaque boîte custom_colors = ['powderblue', 'lightskyblue', 'lightslategray', 'lightsteelblue', 'steelblue'] # Attribution des couleurs aux boîtes et création de la légende for box, color, category in zip(boxes['boxes'], custom_colors, categories): box.set_facecolor(color) # Titre et étiquette des axes plt.title("Box plots de la durée moyenne entre reprise de souscriptions par catégories de souscripteurs") plt.xlabel("Nombre d'années") plt.ylabel("Catégories d'ancienneté") plt.yticks([]) # Création de la légende en utilisant des proxies (éléments de la légende sans affichage réel) legend_proxies = [plt.Rectangle((0, 0), 1, 1, color=color) for color in custom_colors] plt.legend(legend_proxies, categories) # Afficher le boxplot plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    import pandas as pd
    import numpy as np
    
    # Compter le nombre de personnes par catégorie de souscripteur
    df_retraitMS = df_diff_mean6['Catégories souscripteurs'].value_counts().to_frame().reset_index()
    
    # Renommer les colonnes
    df_retraitMS.columns = ['Catégories souscripteurs', "Nombre d'individus"]
    
    # Calculer la moyenne, Q1, Q3 et les whiskers de la variable "Durée actionnariat" pour chaque catégorie
    df_stats = df_diff_mean6.groupby('Catégories souscripteurs')['Différence'].agg(['median', lambda x: np.percentile(x, 25), lambda x: np.percentile(x, 75), lambda x: np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25))]).reset_index()
    
    # Renommer les colonnes de statistiques
    df_stats.columns = ['Catégories souscripteurs', 'Médiane Durée conservation', 'Q1', 'Q3', 'Upper Whiskers']
    
    # Calculer le nombre d'outliers pour chaque catégorie
    df_outliers = df_diff_mean6.groupby('Catégories souscripteurs')['Différence'].apply(lambda x: np.sum((x < np.percentile(x, 25) - 1.5*(np.percentile(x, 75) - np.percentile(x, 25))) | (x > np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25))))).reset_index()
    df_outliers.columns = ['Catégories souscripteurs', 'Nombre d\'outliers']
    
    # Fusionner les DataFrames pour ajouter les statistiques et le nombre d'outliers
    df_retraitMS = pd.merge(df_retraitMS, df_stats, on='Catégories souscripteurs')
    df_retraitMS = pd.merge(df_retraitMS, df_outliers, on='Catégories souscripteurs')
    df_retraitMS.rename(columns={'Médiane Durée conservation': 'Médiane'}, inplace=True)
    
    # Afficher le résultat
    df_retraitMS
    
    import pandas as pd import numpy as np # Compter le nombre de personnes par catégorie de souscripteur df_retraitMS = df_diff_mean6['Catégories souscripteurs'].value_counts().to_frame().reset_index() # Renommer les colonnes df_retraitMS.columns = ['Catégories souscripteurs', "Nombre d'individus"] # Calculer la moyenne, Q1, Q3 et les whiskers de la variable "Durée actionnariat" pour chaque catégorie df_stats = df_diff_mean6.groupby('Catégories souscripteurs')['Différence'].agg(['median', lambda x: np.percentile(x, 25), lambda x: np.percentile(x, 75), lambda x: np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25))]).reset_index() # Renommer les colonnes de statistiques df_stats.columns = ['Catégories souscripteurs', 'Médiane Durée conservation', 'Q1', 'Q3', 'Upper Whiskers'] # Calculer le nombre d'outliers pour chaque catégorie df_outliers = df_diff_mean6.groupby('Catégories souscripteurs')['Différence'].apply(lambda x: np.sum((x < np.percentile(x, 25) - 1.5*(np.percentile(x, 75) - np.percentile(x, 25))) | (x > np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25))))).reset_index() df_outliers.columns = ['Catégories souscripteurs', 'Nombre d\'outliers'] # Fusionner les DataFrames pour ajouter les statistiques et le nombre d'outliers df_retraitMS = pd.merge(df_retraitMS, df_stats, on='Catégories souscripteurs') df_retraitMS = pd.merge(df_retraitMS, df_outliers, on='Catégories souscripteurs') df_retraitMS.rename(columns={'Médiane Durée conservation': 'Médiane'}, inplace=True) # Afficher le résultat df_retraitMS
    Out[ ]:
    Catégories souscripteurs Nombre d'individus Médiane Q1 Q3 Upper Whiskers Nombre d'outliers
    0 2 souscriptions 2370 2.2 0.9 4.6 10.15 89
    1 3 à 5 souscriptions 1050 1.9 1.0 3.2 6.50 18
    2 6 à 10 souscriptions 73 0.9 0.6 1.4 2.60 0
    3 10 souscriptions et plus 21 1.0 0.4 1.2 2.40 0
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    display(HTML('<center><h2><u>Evolution des intervalles de durée entre les différents rangs de reprises de souscriptions (en année)</u></h2></center>'))
    
    from IPython.display import display, Markdown, HTML display(HTML('

    Evolution des intervalles de durée entre les différents rangs de reprises de souscriptions (en année)

    '))

    Evolution des intervalles de durée entre les différents rangs de reprises de souscriptions (en année)

    In [ ]:
    Copied!
    df_var_tps_reprise = df_var_tps_reprise[df_var_tps_reprise["Nature du mouvement"] == "Souscription"]
    df_var_tps_reprise['Date du Mouvement'] = pd.to_datetime(df_var_tps_reprise['Date du Mouvement'])
    df_var_tps_reprise = df_var_tps_reprise[['ID du contact', 'Date du Mouvement']]
    df_var_tps_reprise['nb souscriptions'] = df_var_tps_reprise['ID du contact'].map(df_var_tps_reprise ['ID du contact'].value_counts())
    df_var_tps_reprise = df_var_tps_reprise.sort_values(by=['ID du contact', 'Date du Mouvement'])
    df_var_tps_reprise = df_var_tps_reprise[(df_var_tps_reprise["nb souscriptions"] <= 10) & (df_var_tps_reprise["nb souscriptions"] > 1)]
    df_var_tps_reprise = pd.pivot_table(df_var_tps_reprise, index='ID du contact', columns=df_var_tps_reprise.groupby('ID du contact').cumcount() + 1,
    values=["Date du Mouvement"],
    aggfunc='first')
    df_var_tps_reprise.columns = [f'{col[0]}_{col[1]}' for col in df_var_tps_reprise.columns]
    df_var_tps_reprise.reset_index(inplace=True)
    # Créer les colonnes de différences de nombres d'actions
    for i in range(2, 11):
        df_var_tps_reprise[f'intervalle_souscriptions_{i}_{i-1}'] = df_var_tps_reprise[f'Date du Mouvement_{i}'] - df_var_tps_reprise[f'Date du Mouvement_{i-1}']
    
    # Liste des colonnes d'intervalle à convertir
    colonnes_intervalle = [f'intervalle_souscriptions_{i}_{i-1}' for i in range(2, 11)]
    
    # Convertir les intervalles en années
    for colonne in colonnes_intervalle:
        df_var_tps_reprise[colonne] = df_var_tps_reprise[colonne].apply(lambda x: np.nan if pd.isnull(x) else x.total_seconds() / 31536000)  # 31,536,000 secondes dans une année
    # Supprimer les colonnes du tableau
    
    colonnes_a_supprimer = [
        f"Date du Mouvement_{i}" for i in range(1, 11)
    ]
    
    # calculer les variations moyenne par colonnes 
    df_var_tps_reprise.drop(colonnes_a_supprimer, axis=1, inplace=True)
    intervalles = df_var_tps_reprise.drop(columns='ID du contact').mean(skipna=True).to_frame()
    import matplotlib.pyplot as plt
    
    # Données pour l'axe x (colonnes)
    colonnes = intervalles.index
    
    # Données pour l'axe y (moyennes)
    moyennes_values = intervalles.values
    
    # Créer le graphique
    plt.figure(figsize=(10, 6))
    plt.plot(colonnes, moyennes_values, marker='o', linestyle='-', color='darkblue')
    plt.axhline(y=0, color='red', linestyle='--', linewidth=1)  # Ligne du 0 en rouge
    plt.xlabel('Colonnes')
    plt.ylabel('Variations intervalles entre reprises de souscritpions')
    plt.title('Variations moyennes totale des intervalles  en année entre nième souscriptions (jusqu\'à 10)')
    plt.xticks(rotation=60)
    plt.grid(True)
    
    # Annoter chaque point avec sa valeur
    for i, txt in enumerate(moyennes_values):
        plt.text(colonnes[i], txt[0] + 0.2, f'{txt[0]:.2f}', ha='center', va='bottom', color='black', fontweight='normal')
    
    
    # Afficher le graphique
    plt.tight_layout()
    plt.show()
    
    df_var_tps_reprise = df_var_tps_reprise[df_var_tps_reprise["Nature du mouvement"] == "Souscription"] df_var_tps_reprise['Date du Mouvement'] = pd.to_datetime(df_var_tps_reprise['Date du Mouvement']) df_var_tps_reprise = df_var_tps_reprise[['ID du contact', 'Date du Mouvement']] df_var_tps_reprise['nb souscriptions'] = df_var_tps_reprise['ID du contact'].map(df_var_tps_reprise ['ID du contact'].value_counts()) df_var_tps_reprise = df_var_tps_reprise.sort_values(by=['ID du contact', 'Date du Mouvement']) df_var_tps_reprise = df_var_tps_reprise[(df_var_tps_reprise["nb souscriptions"] <= 10) & (df_var_tps_reprise["nb souscriptions"] > 1)] df_var_tps_reprise = pd.pivot_table(df_var_tps_reprise, index='ID du contact', columns=df_var_tps_reprise.groupby('ID du contact').cumcount() + 1, values=["Date du Mouvement"], aggfunc='first') df_var_tps_reprise.columns = [f'{col[0]}_{col[1]}' for col in df_var_tps_reprise.columns] df_var_tps_reprise.reset_index(inplace=True) # Créer les colonnes de différences de nombres d'actions for i in range(2, 11): df_var_tps_reprise[f'intervalle_souscriptions_{i}_{i-1}'] = df_var_tps_reprise[f'Date du Mouvement_{i}'] - df_var_tps_reprise[f'Date du Mouvement_{i-1}'] # Liste des colonnes d'intervalle à convertir colonnes_intervalle = [f'intervalle_souscriptions_{i}_{i-1}' for i in range(2, 11)] # Convertir les intervalles en années for colonne in colonnes_intervalle: df_var_tps_reprise[colonne] = df_var_tps_reprise[colonne].apply(lambda x: np.nan if pd.isnull(x) else x.total_seconds() / 31536000) # 31,536,000 secondes dans une année # Supprimer les colonnes du tableau colonnes_a_supprimer = [ f"Date du Mouvement_{i}" for i in range(1, 11) ] # calculer les variations moyenne par colonnes df_var_tps_reprise.drop(colonnes_a_supprimer, axis=1, inplace=True) intervalles = df_var_tps_reprise.drop(columns='ID du contact').mean(skipna=True).to_frame() import matplotlib.pyplot as plt # Données pour l'axe x (colonnes) colonnes = intervalles.index # Données pour l'axe y (moyennes) moyennes_values = intervalles.values # Créer le graphique plt.figure(figsize=(10, 6)) plt.plot(colonnes, moyennes_values, marker='o', linestyle='-', color='darkblue') plt.axhline(y=0, color='red', linestyle='--', linewidth=1) # Ligne du 0 en rouge plt.xlabel('Colonnes') plt.ylabel('Variations intervalles entre reprises de souscritpions') plt.title('Variations moyennes totale des intervalles en année entre nième souscriptions (jusqu\'à 10)') plt.xticks(rotation=60) plt.grid(True) # Annoter chaque point avec sa valeur for i, txt in enumerate(moyennes_values): plt.text(colonnes[i], txt[0] + 0.2, f'{txt[0]:.2f}', ha='center', va='bottom', color='black', fontweight='normal') # Afficher le graphique plt.tight_layout() plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    display(HTML("<div style='page-break-before: always;'></div>"))
    
    display(HTML('<center><h2><u>Part des rachats parmi les catégories de souscripteurs (mono ou multi-souscripteurs)</u></h2></center>'))
    
    from IPython.display import display, Markdown, HTML display(HTML("
    ")) display(HTML('

    Part des rachats parmi les catégories de souscripteurs (mono ou multi-souscripteurs)

    '))

    Part des rachats parmi les catégories de souscripteurs (mono ou multi-souscripteurs)

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    display(HTML('<h3>Effectifs croisés des personnes ayant fait un rachat parmi les mono et multi-souscripteurs</h3>'))
    
    from IPython.display import display, Markdown, HTML display(HTML('

    Effectifs croisés des personnes ayant fait un rachat parmi les mono et multi-souscripteurs

    '))

    Effectifs croisés des personnes ayant fait un rachat parmi les mono et multi-souscripteurs

    In [ ]:
    Copied!
    twenty4_months_ago = datetime.now() - timedelta(days=730)
    df_partrachat['RFM-Date Dernier Don'] = pd.to_datetime(df_partrachat['RFM-Date Dernier Don'], format='%d/%m/%Y')
    df_partrachat.loc[:, "multi-casquette ?"] = df_partrachat.apply(lambda row: "Actionnaire-donateur" if row["Actionnaire ?"] == 1 and (row["Donateur N"] == 1 or row['RFM-Date Dernier Don'] >= twenty4_months_ago)  and row["adhérent N"] == 0 and row['adhérent N-1'] == 0
                                                else "Actionnaire-adhérent" if row["Actionnaire ?"] == 1 and (row["adhérent N"] == 1 or row['adhérent N-1'] == 1) and row["Donateur N"] == 0 and row['RFM-Date Dernier Don'] < twenty4_months_ago
                                                else "Triple-engagement" if row["Actionnaire ?"] == 1 and (row["adhérent N"] == 1 or row['adhérent N-1'] == 1) and (row["Donateur N"] == 1 or row['RFM-Date Dernier Don'] >= twenty4_months_ago)
                                                else "Actionnaire uniquement", axis=1)
    
    conditions = [
        (df_partrachat['âge'] < 25),
        (df_partrachat['âge'] < 40),
        (df_partrachat['âge'] < 60)
    ]
    
    choices = ['0-25 ans', '25-40 ans', '40-60 ans']
    
    df_partrachat['catégories âge'] = np.select(conditions, choices, default='60 ans et plus')
    
    
    df_partrachat['RFM-Date Première Souscription'] = pd.to_datetime(df_partrachat['RFM-Date Première Souscription'], dayfirst=True)
    
    conditions = [
        (df_partrachat['RFM-Date Première Souscription'] <= pd.to_datetime('2012')),
        (df_partrachat['RFM-Date Première Souscription'] <= pd.to_datetime('2017'))
    ]
    
    choices = ['Nouvel actionnaire en 2012 ou moins', 'Nouvel actionnaire entre 2012 à 2017']
    
    df_partrachat['ancienneté actionnaires'] = np.select(conditions, choices, default='Nouvel actionnaire depuis 2017 ou plus')
    df_partrachat['RFM-Date Première Souscription'] = df_partrachat['RFM-Date Première Souscription'].astype(str)
    df_partrachatrep = df_partrachat.groupby(['ID du contact', 'Nature du mouvement']).size().reset_index(name='Nombre d\'interactions')
    df_partrachatrep['multi-souscripteurs ?'] = df_partrachatrep.groupby('ID du contact')['Nature du mouvement'].transform(lambda x: (x == 'Souscription').any()) & (df_partrachatrep.groupby('ID du contact')['Nombre d\'interactions'].transform(lambda x: (x > 1).any()))
    df_partrachatrep['Rachat ?'] = df_partrachatrep.groupby('ID du contact')['Nature du mouvement'].transform(lambda x: (x == 'Rachat').any()) 
    df_partrachatrep = df_partrachatrep.drop_duplicates(subset = "ID du contact")
    df_partrachatrep["multi-souscripteurs ?"] = df_partrachatrep["multi-souscripteurs ?"].replace({True: "Multi-souscripteurs", False: "Mono-souscripteurs"})
    df_partrachatrep["Rachat ?"] = df_partrachatrep["Rachat ?"].replace({True: "Ont fait un rachat", False: "Pas de rachat"})
    df_partrachatrep = pd.crosstab(index=df_partrachatrep['multi-souscripteurs ?'], columns=df_partrachatrep['Rachat ?'], margins=True, margins_name='Total')
    df_partrachatrep 
    
    twenty4_months_ago = datetime.now() - timedelta(days=730) df_partrachat['RFM-Date Dernier Don'] = pd.to_datetime(df_partrachat['RFM-Date Dernier Don'], format='%d/%m/%Y') df_partrachat.loc[:, "multi-casquette ?"] = df_partrachat.apply(lambda row: "Actionnaire-donateur" if row["Actionnaire ?"] == 1 and (row["Donateur N"] == 1 or row['RFM-Date Dernier Don'] >= twenty4_months_ago) and row["adhérent N"] == 0 and row['adhérent N-1'] == 0 else "Actionnaire-adhérent" if row["Actionnaire ?"] == 1 and (row["adhérent N"] == 1 or row['adhérent N-1'] == 1) and row["Donateur N"] == 0 and row['RFM-Date Dernier Don'] < twenty4_months_ago else "Triple-engagement" if row["Actionnaire ?"] == 1 and (row["adhérent N"] == 1 or row['adhérent N-1'] == 1) and (row["Donateur N"] == 1 or row['RFM-Date Dernier Don'] >= twenty4_months_ago) else "Actionnaire uniquement", axis=1) conditions = [ (df_partrachat['âge'] < 25), (df_partrachat['âge'] < 40), (df_partrachat['âge'] < 60) ] choices = ['0-25 ans', '25-40 ans', '40-60 ans'] df_partrachat['catégories âge'] = np.select(conditions, choices, default='60 ans et plus') df_partrachat['RFM-Date Première Souscription'] = pd.to_datetime(df_partrachat['RFM-Date Première Souscription'], dayfirst=True) conditions = [ (df_partrachat['RFM-Date Première Souscription'] <= pd.to_datetime('2012')), (df_partrachat['RFM-Date Première Souscription'] <= pd.to_datetime('2017')) ] choices = ['Nouvel actionnaire en 2012 ou moins', 'Nouvel actionnaire entre 2012 à 2017'] df_partrachat['ancienneté actionnaires'] = np.select(conditions, choices, default='Nouvel actionnaire depuis 2017 ou plus') df_partrachat['RFM-Date Première Souscription'] = df_partrachat['RFM-Date Première Souscription'].astype(str) df_partrachatrep = df_partrachat.groupby(['ID du contact', 'Nature du mouvement']).size().reset_index(name='Nombre d\'interactions') df_partrachatrep['multi-souscripteurs ?'] = df_partrachatrep.groupby('ID du contact')['Nature du mouvement'].transform(lambda x: (x == 'Souscription').any()) & (df_partrachatrep.groupby('ID du contact')['Nombre d\'interactions'].transform(lambda x: (x > 1).any())) df_partrachatrep['Rachat ?'] = df_partrachatrep.groupby('ID du contact')['Nature du mouvement'].transform(lambda x: (x == 'Rachat').any()) df_partrachatrep = df_partrachatrep.drop_duplicates(subset = "ID du contact") df_partrachatrep["multi-souscripteurs ?"] = df_partrachatrep["multi-souscripteurs ?"].replace({True: "Multi-souscripteurs", False: "Mono-souscripteurs"}) df_partrachatrep["Rachat ?"] = df_partrachatrep["Rachat ?"].replace({True: "Ont fait un rachat", False: "Pas de rachat"}) df_partrachatrep = pd.crosstab(index=df_partrachatrep['multi-souscripteurs ?'], columns=df_partrachatrep['Rachat ?'], margins=True, margins_name='Total') df_partrachatrep
    Out[ ]:
    Rachat ? Ont fait un rachat Pas de rachat Total
    multi-souscripteurs ?
    Mono-souscripteurs 1717 5831 7548
    Multi-souscripteurs 780 3462 4242
    Total 2497 9293 11790
    In [ ]:
    Copied!
    import pandas as pd
    import matplotlib.pyplot as plt
    
    # Supposons que vous avez déjà créé votre table croisée df_partrachatrep
    
    # Calculez les pourcentages pour chaque catégorie de "Rachat ?"
    df_percentage = df_partrachatrep.div(df_partrachatrep['Total'], axis=0) * 100
    
    # Créez un graphique en barres empilées à 100 %
    ax = df_percentage.iloc[:-1, :-1].plot(kind='bar', stacked=True, figsize=(10, 6))
    
    # Ajoutez des étiquettes et un titre
    plt.xlabel('Multi-souscripteurs / Mono-souscripteurs')
    plt.ylabel('Pourcentage')
    plt.title('Rachat parmi les mono et multi-souscripteurs ')
    
    # Affichez les étiquettes de pourcentage pour chaque segment empilé
    for p in ax.patches:
        width, height = p.get_width(), p.get_height()
        x, y = p.get_xy() 
        ax.annotate(f'{height:.1f}%', (x + width/2, y + height/2), ha='center', va='center')
    
    # Affichez la légende
    plt.legend(title='Rachat ?')
    
    # Affichez le graphique
    plt.show()
    
    import pandas as pd import matplotlib.pyplot as plt # Supposons que vous avez déjà créé votre table croisée df_partrachatrep # Calculez les pourcentages pour chaque catégorie de "Rachat ?" df_percentage = df_partrachatrep.div(df_partrachatrep['Total'], axis=0) * 100 # Créez un graphique en barres empilées à 100 % ax = df_percentage.iloc[:-1, :-1].plot(kind='bar', stacked=True, figsize=(10, 6)) # Ajoutez des étiquettes et un titre plt.xlabel('Multi-souscripteurs / Mono-souscripteurs') plt.ylabel('Pourcentage') plt.title('Rachat parmi les mono et multi-souscripteurs ') # Affichez les étiquettes de pourcentage pour chaque segment empilé for p in ax.patches: width, height = p.get_width(), p.get_height() x, y = p.get_xy() ax.annotate(f'{height:.1f}%', (x + width/2, y + height/2), ha='center', va='center') # Affichez la légende plt.legend(title='Rachat ?') # Affichez le graphique plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    display(HTML("<div style='page-break-before: always;'></div>"))
    
    display(HTML('<center><h2><u>Durées moyennes entre interactions sur un contrat (concerne les personnes ayant fait des rachats d\'actions)</u></h2></center>'))
    
    from IPython.display import display, Markdown, HTML display(HTML("
    ")) display(HTML('

    Durées moyennes entre interactions sur un contrat (concerne les personnes ayant fait des rachats d\'actions)

    '))

    Durées moyennes entre interactions sur un contrat (concerne les personnes ayant fait des rachats d'actions)

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>On calcule l'écart entre la date de début du contrat et la date de rachat d'actions. On fait ensuite une moyenne individuelle de ces écarts</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    On calcule l'écart entre la date de début du contrat et la date de rachat d'actions. On fait ensuite une moyenne individuelle de ces écarts

    "))

    On calcule l'écart entre la date de début du contrat et la date de rachat d'actions. On fait ensuite une moyenne individuelle de ces écarts

    In [ ]:
    Copied!
    df.loc[:, "multi-casquette ?"] = df.apply(lambda row: "Actionnaire-donateur" if row["Actionnaire ?"] == 1 and (row["Donateur N"] == 1 or row['RFM-Date Dernier Don'] >= twenty4_months_ago)  and row["adhérent N"] == 0 and row['adhérent N-1'] == 0
                                                else "Actionnaire-adhérent" if row["Actionnaire ?"] == 1 and (row["adhérent N"] == 1 or row['adhérent N-1'] == 1) and row["Donateur N"] == 0 and row['RFM-Date Dernier Don'] < twenty4_months_ago
                                                else "Triple-engagement" if row["Actionnaire ?"] == 1 and (row["adhérent N"] == 1 or row['adhérent N-1'] == 1) and (row["Donateur N"] == 1 or row['RFM-Date Dernier Don'] >= twenty4_months_ago)
                                                else "Actionnaire uniquement", axis=1)
    df_durée_conserv = df[df["Nature du mouvement"] == "Rachat"]
    df_durée_conservtest = df[(df["Nature du mouvement"] == "Rachat") & (df["multi-casquette ?"] == "Actionnaire-adhérent")]
    
    df.loc[:, "multi-casquette ?"] = df.apply(lambda row: "Actionnaire-donateur" if row["Actionnaire ?"] == 1 and (row["Donateur N"] == 1 or row['RFM-Date Dernier Don'] >= twenty4_months_ago) and row["adhérent N"] == 0 and row['adhérent N-1'] == 0 else "Actionnaire-adhérent" if row["Actionnaire ?"] == 1 and (row["adhérent N"] == 1 or row['adhérent N-1'] == 1) and row["Donateur N"] == 0 and row['RFM-Date Dernier Don'] < twenty4_months_ago else "Triple-engagement" if row["Actionnaire ?"] == 1 and (row["adhérent N"] == 1 or row['adhérent N-1'] == 1) and (row["Donateur N"] == 1 or row['RFM-Date Dernier Don'] >= twenty4_months_ago) else "Actionnaire uniquement", axis=1) df_durée_conserv = df[df["Nature du mouvement"] == "Rachat"] df_durée_conservtest = df[(df["Nature du mouvement"] == "Rachat") & (df["multi-casquette ?"] == "Actionnaire-adhérent")]
    In [ ]:
    Copied!
    from datetime import datetime, timedelta
    df_durée_conserv = df_durée_conserv.groupby("ID du contact")["durée conservation"].mean().to_frame().reset_index()
    df_durée_conserv = df_durée_conserv.merge(df2[["ID du contact",'Catégories souscripteurs','multi-souscripteur ?','ancienneté actionnaires','catégories âge',"multi-casquette ?"]], on='ID du contact', how='left')
    df_durée_conserv = df_durée_conserv.drop_duplicates(subset = "ID du contact")
    df_durée_conserv['multi-souscripteur ?'] = df_durée_conserv['multi-souscripteur ?'].replace({True: "multi-souscripteurs", False: "souscripteurs uniques"})
    df_durée_conserv = df_durée_conserv.drop(df_durée_conserv[df_durée_conserv["durée conservation"] < timedelta(days=0)].index)
    
    from datetime import datetime, timedelta df_durée_conserv = df_durée_conserv.groupby("ID du contact")["durée conservation"].mean().to_frame().reset_index() df_durée_conserv = df_durée_conserv.merge(df2[["ID du contact",'Catégories souscripteurs','multi-souscripteur ?','ancienneté actionnaires','catégories âge',"multi-casquette ?"]], on='ID du contact', how='left') df_durée_conserv = df_durée_conserv.drop_duplicates(subset = "ID du contact") df_durée_conserv['multi-souscripteur ?'] = df_durée_conserv['multi-souscripteur ?'].replace({True: "multi-souscripteurs", False: "souscripteurs uniques"}) df_durée_conserv = df_durée_conserv.drop(df_durée_conserv[df_durée_conserv["durée conservation"] < timedelta(days=0)].index)
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Durée moyenne totale entre interactions sur un contrats </h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Durée moyenne totale entre interactions sur un contrats

    "))

    Durée moyenne totale entre interactions sur un contrats

    In [ ]:
    Copied!
    moyenne_jours = df_durée_conserv['durée conservation'].mean().days
    moyenne_annees = moyenne_jours / 365.25
    print(f"Moyenne des intervalles entre interractions : {moyenne_annees:.2f} années")
    
    moyenne_jours = df_durée_conserv['durée conservation'].mean().days moyenne_annees = moyenne_jours / 365.25 print(f"Moyenne des intervalles entre interractions : {moyenne_annees:.2f} années")
    Moyenne des intervalles entre interractions : 6.92 années
    
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Clé de lecture : Depuis la date d'activation d'un de leurs contrats de souscription, les souscripteurs ont en moyenne attendu 6, 52 années avant de racheter des actions sur ces mêmes contrats</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Clé de lecture : Depuis la date d'activation d'un de leurs contrats de souscription, les souscripteurs ont en moyenne attendu 6, 52 années avant de racheter des actions sur ces mêmes contrats

    "))

    Clé de lecture : Depuis la date d'activation d'un de leurs contrats de souscription, les souscripteurs ont en moyenne attendu 6, 52 années avant de racheter des actions sur ces mêmes contrats

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Durée moyenne entre interactions sur un contrats  par catégories du souscripteurs</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Durée moyenne entre interactions sur un contrats par catégories du souscripteurs

    "))

    Durée moyenne entre interactions sur un contrats par catégories du souscripteurs

    In [ ]:
    Copied!
    count_per_category = df_durée_conserv.groupby('Catégories souscripteurs').size().reset_index(name='Nombre de personnes')
    df_durée_conserv_mean_catsous= df_durée_conserv.groupby('Catégories souscripteurs')["durée conservation"].mean().dt.total_seconds() / (365.25 * 24 * 60 * 60)
    df_durée_conserv_mean_catsous = df_durée_conserv_mean_catsous.round(1).to_frame(name="Moyenne des intervalles entre interraction  (années)")
    df_durée_conserv_mean_catsous = df_durée_conserv_mean_catsous.merge(count_per_category, on='Catégories souscripteurs', how='left')
    ordre_categories_souscripteurs = ['1 souscription', '2 souscriptions', '3 à 5 souscriptions', '6 à 10 souscriptions', '10 souscriptions et plus']
    df_durée_conserv_mean_catsous = df_durée_conserv_mean_catsous.set_index('Catégories souscripteurs').loc[ordre_categories_souscripteurs].reset_index()
    df_durée_conserv_mean_catsous
    
    count_per_category = df_durée_conserv.groupby('Catégories souscripteurs').size().reset_index(name='Nombre de personnes') df_durée_conserv_mean_catsous= df_durée_conserv.groupby('Catégories souscripteurs')["durée conservation"].mean().dt.total_seconds() / (365.25 * 24 * 60 * 60) df_durée_conserv_mean_catsous = df_durée_conserv_mean_catsous.round(1).to_frame(name="Moyenne des intervalles entre interraction (années)") df_durée_conserv_mean_catsous = df_durée_conserv_mean_catsous.merge(count_per_category, on='Catégories souscripteurs', how='left') ordre_categories_souscripteurs = ['1 souscription', '2 souscriptions', '3 à 5 souscriptions', '6 à 10 souscriptions', '10 souscriptions et plus'] df_durée_conserv_mean_catsous = df_durée_conserv_mean_catsous.set_index('Catégories souscripteurs').loc[ordre_categories_souscripteurs].reset_index() df_durée_conserv_mean_catsous
    Out[ ]:
    Catégories souscripteurs Moyenne des intervalles entre interraction (années) Nombre de personnes
    0 1 souscription 7.1 656
    1 2 souscriptions 6.5 331
    2 3 à 5 souscriptions 6.5 141
    3 6 à 10 souscriptions 6.9 49
    4 10 souscriptions et plus 5.5 7
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Durée moyenne entre interactions sur un contrats  par ancienneté de l'actionnaire</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Durée moyenne entre interactions sur un contrats par ancienneté de l'actionnaire

    "))

    Durée moyenne entre interactions sur un contrats par ancienneté de l'actionnaire

    In [ ]:
    Copied!
    ordre_categories_ancienneté = ['Nouvel actionnaire depuis 2017 ou plus', 'Nouvel actionnaire entre 2012 à 2017', 'Nouvel actionnaire en 2012 ou moins']
    
    
    count_per_category = df_durée_conserv.groupby('ancienneté actionnaires').size().reset_index(name='Nombre de personnes')
    df_durée_conserv_mean_ancienneté = df_durée_conserv.groupby("ancienneté actionnaires")["durée conservation"].mean().dt.total_seconds() / (365.25 * 24 * 60 * 60)
    df_durée_conserv_mean_ancienneté = df_durée_conserv_mean_ancienneté.round(1).to_frame(name="Moyenne des intervalles entre interractions  (années)")
    df_durée_conserv_mean_ancienneté = df_durée_conserv_mean_ancienneté.merge(count_per_category, on='ancienneté actionnaires', how='left')
    df_durée_conserv_mean_ancienneté= df_durée_conserv_mean_ancienneté.reindex(ordre_categories_ancienneté)
    
    ordre_categories_ancienneté = ['Nouvel actionnaire depuis 2017 ou plus', 'Nouvel actionnaire entre 2012 à 2017', 'Nouvel actionnaire en 2012 ou moins'] count_per_category = df_durée_conserv.groupby('ancienneté actionnaires').size().reset_index(name='Nombre de personnes') df_durée_conserv_mean_ancienneté = df_durée_conserv.groupby("ancienneté actionnaires")["durée conservation"].mean().dt.total_seconds() / (365.25 * 24 * 60 * 60) df_durée_conserv_mean_ancienneté = df_durée_conserv_mean_ancienneté.round(1).to_frame(name="Moyenne des intervalles entre interractions (années)") df_durée_conserv_mean_ancienneté = df_durée_conserv_mean_ancienneté.merge(count_per_category, on='ancienneté actionnaires', how='left') df_durée_conserv_mean_ancienneté= df_durée_conserv_mean_ancienneté.reindex(ordre_categories_ancienneté)
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Durée moyenne entre interactions sur un contrat par catégories d'âge </h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Durée moyenne entre interactions sur un contrat par catégories d'âge

    "))

    Durée moyenne entre interactions sur un contrat par catégories d'âge

    In [ ]:
    Copied!
    count_per_category = df_durée_conserv.groupby('catégories âge').size().reset_index(name='Nombre de personnes')
    df_durée_conserv_mean_age= df_durée_conserv.groupby('catégories âge')["durée conservation"].mean().dt.total_seconds() / (365.25 * 24 * 60 * 60)
    df_durée_conserv_mean_age = df_durée_conserv_mean_age.round(1).to_frame(name="Moyenne des intervalles entre interactions  (années)")
    df_durée_conserv_mean_age = df_durée_conserv_mean_age.merge(count_per_category, on='catégories âge', how='left')
    df_durée_conserv_mean_age
    
    count_per_category = df_durée_conserv.groupby('catégories âge').size().reset_index(name='Nombre de personnes') df_durée_conserv_mean_age= df_durée_conserv.groupby('catégories âge')["durée conservation"].mean().dt.total_seconds() / (365.25 * 24 * 60 * 60) df_durée_conserv_mean_age = df_durée_conserv_mean_age.round(1).to_frame(name="Moyenne des intervalles entre interactions (années)") df_durée_conserv_mean_age = df_durée_conserv_mean_age.merge(count_per_category, on='catégories âge', how='left') df_durée_conserv_mean_age
    Out[ ]:
    catégories âge Moyenne des intervalles entre interactions (années) Nombre de personnes
    0 0-25 ans 6.9 314
    1 25-40 ans 6.7 199
    2 40-60 ans 7.0 264
    3 60 ans et plus 6.8 407
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Durée moyenne entre interactions sur un contrat par multi-casquettes ? </h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Durée moyenne entre interactions sur un contrat par multi-casquettes ?

    "))

    Durée moyenne entre interactions sur un contrat par multi-casquettes ?

    In [ ]:
    Copied!
    count_per_category = df_durée_conserv.groupby('multi-casquette ?').size().reset_index(name='Nombre de personnes')
    df_durée_conserv_mean_MC= df_durée_conserv.groupby('multi-casquette ?')["durée conservation"].mean().dt.total_seconds() / (365.25 * 24 * 60 * 60)
    df_durée_conserv_mean_MC = df_durée_conserv_mean_MC.round(1).to_frame(name="Moyenne des intervalles entre interactions  (années)")
    df_durée_conserv_mean_MC = df_durée_conserv_mean_MC.merge(count_per_category, on='multi-casquette ?', how='left')
    df_durée_conserv_mean_MC
    
    count_per_category = df_durée_conserv.groupby('multi-casquette ?').size().reset_index(name='Nombre de personnes') df_durée_conserv_mean_MC= df_durée_conserv.groupby('multi-casquette ?')["durée conservation"].mean().dt.total_seconds() / (365.25 * 24 * 60 * 60) df_durée_conserv_mean_MC = df_durée_conserv_mean_MC.round(1).to_frame(name="Moyenne des intervalles entre interactions (années)") df_durée_conserv_mean_MC = df_durée_conserv_mean_MC.merge(count_per_category, on='multi-casquette ?', how='left') df_durée_conserv_mean_MC
    Out[ ]:
    multi-casquette ? Moyenne des intervalles entre interactions (années) Nombre de personnes
    0 Actionnaire uniquement 7.1 264
    1 Actionnaire-adhérent 6.7 349
    2 Actionnaire-donateur 6.7 156
    3 Triple-engagement 6.9 415
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Durée moyenne entre interactions sur un contrat par multi-souscripteurs ? </h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Durée moyenne entre interactions sur un contrat par multi-souscripteurs ?

    "))

    Durée moyenne entre interactions sur un contrat par multi-souscripteurs ?

    In [ ]:
    Copied!
    count_per_category = df_durée_conserv.groupby('multi-souscripteur ?').size().reset_index(name='Nombre de personnes')
    df_durée_conserv_mean_MS= df_durée_conserv.groupby('multi-souscripteur ?')["durée conservation"].mean().dt.total_seconds() / (365.25 * 24 * 60 * 60)
    df_durée_conserv_mean_MS = df_durée_conserv_mean_MS.round(1).to_frame(name="Moyenne des intervalles entre interactions  (années)")
    df_durée_conserv_mean_MS = df_durée_conserv_mean_MS.merge(count_per_category, on='multi-souscripteur ?', how='left')
    df_durée_conserv_mean_MS
    
    count_per_category = df_durée_conserv.groupby('multi-souscripteur ?').size().reset_index(name='Nombre de personnes') df_durée_conserv_mean_MS= df_durée_conserv.groupby('multi-souscripteur ?')["durée conservation"].mean().dt.total_seconds() / (365.25 * 24 * 60 * 60) df_durée_conserv_mean_MS = df_durée_conserv_mean_MS.round(1).to_frame(name="Moyenne des intervalles entre interactions (années)") df_durée_conserv_mean_MS = df_durée_conserv_mean_MS.merge(count_per_category, on='multi-souscripteur ?', how='left') df_durée_conserv_mean_MS
    Out[ ]:
    multi-souscripteur ? Moyenne des intervalles entre interactions (années) Nombre de personnes
    0 multi-souscripteurs 6.6 528
    1 souscripteurs uniques 7.1 656
    In [ ]:
    Copied!
    import matplotlib.pyplot as plt
    import numpy as np
    df_durée_conserv['durée conservation'] = df_durée_conserv['durée conservation'] / np.timedelta64(1, 'W')
    df_durée_conserv = df_durée_conserv/ 52
    df_durée_conserv['durée conservation'] = df_durée_conserv['durée conservation'].round(1)
    # Calculer la médiane, Q1 et Q3
    median = np.median(df_durée_conserv['durée conservation'])
    q1 = np.percentile(df_durée_conserv['durée conservation'], 25)
    q3 = np.percentile(df_durée_conserv['durée conservation'], 75)
    
    # Calculer les limites inférieures et supérieures des whiskers
    iqr = q3 - q1
    lower_whisker = q1 - 1.5 * iqr
    upper_whisker = q3 + 1.5 * iqr
    upper_whisker = upper_whisker.round(1)
    # Créer le box plot horizontalement
    plt.figure(figsize=(8, 6))
    plt.boxplot(df_durée_conserv['durée conservation'], vert=False)
    
    # Calculer le nombre d'outliers
    whiskers = plt.boxplot(df_durée_conserv['durée conservation'], vert=False)['fliers']
    num_outliers = len(whiskers[0].get_data()[0])
    
    # Ajouter les valeurs de la médiane, Q1, Q3, limites des whiskers au graphique
    plt.text(0.02, 0.9, f"Médiane: {median}", transform=plt.gca().transAxes)
    plt.text(0.02, 0.8, f"Q1: {q1}", transform=plt.gca().transAxes)
    plt.text(0.02, 0.7, f"Q3: {q3}", transform=plt.gca().transAxes)
    plt.text(0.5, 0.8, f"borne supérieur du boxplot: {upper_whisker}", transform=plt.gca().transAxes)
    plt.text(0.5, 0.9, f"Outliers: {num_outliers}", transform=plt.gca().transAxes)
    
    # Titre et étiquette de l'axe y
    plt.title("Durées moyennes totales entre interactions sur un contrats")
    plt.xlabel("Nombre d'années")
    plt.ylabel("")
    plt.yticks([])
    # Afficher le box plot
    plt.show()
    
    import matplotlib.pyplot as plt import numpy as np df_durée_conserv['durée conservation'] = df_durée_conserv['durée conservation'] / np.timedelta64(1, 'W') df_durée_conserv = df_durée_conserv/ 52 df_durée_conserv['durée conservation'] = df_durée_conserv['durée conservation'].round(1) # Calculer la médiane, Q1 et Q3 median = np.median(df_durée_conserv['durée conservation']) q1 = np.percentile(df_durée_conserv['durée conservation'], 25) q3 = np.percentile(df_durée_conserv['durée conservation'], 75) # Calculer les limites inférieures et supérieures des whiskers iqr = q3 - q1 lower_whisker = q1 - 1.5 * iqr upper_whisker = q3 + 1.5 * iqr upper_whisker = upper_whisker.round(1) # Créer le box plot horizontalement plt.figure(figsize=(8, 6)) plt.boxplot(df_durée_conserv['durée conservation'], vert=False) # Calculer le nombre d'outliers whiskers = plt.boxplot(df_durée_conserv['durée conservation'], vert=False)['fliers'] num_outliers = len(whiskers[0].get_data()[0]) # Ajouter les valeurs de la médiane, Q1, Q3, limites des whiskers au graphique plt.text(0.02, 0.9, f"Médiane: {median}", transform=plt.gca().transAxes) plt.text(0.02, 0.8, f"Q1: {q1}", transform=plt.gca().transAxes) plt.text(0.02, 0.7, f"Q3: {q3}", transform=plt.gca().transAxes) plt.text(0.5, 0.8, f"borne supérieur du boxplot: {upper_whisker}", transform=plt.gca().transAxes) plt.text(0.5, 0.9, f"Outliers: {num_outliers}", transform=plt.gca().transAxes) # Titre et étiquette de l'axe y plt.title("Durées moyennes totales entre interactions sur un contrats") plt.xlabel("Nombre d'années") plt.ylabel("") plt.yticks([]) # Afficher le box plot plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    # Créer les groupes pour le boxplot et inverser l'ordre des données
    grouped_data = df_durée_conserv.groupby('Catégories souscripteurs')['durée conservation'].apply(list)
    
    # Créer le boxplot en inversant l'ordre des positions
    plt.figure(figsize=(8, 6))
    boxes = plt.boxplot(grouped_data, vert=False, patch_artist=True)
    custom_order = ['10 souscriptions et plus', '6 à 10 souscriptions', '3 à 5 souscriptions', '2 souscriptions', '1 souscription']
    grouped_data = grouped_data.reindex(custom_order)
    # Récupérer les étiquettes de catégories
    categories = grouped_data.index
    # Couleurs personnalisées pour chaque boîte
    custom_colors = ['powderblue', 'lightskyblue', 'lightslategray', 'lightsteelblue', 'steelblue']
    
    
    
    # Attribution des couleurs aux boîtes
    for box, color in zip(boxes['boxes'], custom_colors):
        box.set_facecolor(color)
    
    # Titre et étiquette des axes
    plt.title("Durées moyennes entre interactions sur un contrat par catégories des souscripteurs")
    plt.xlabel("Nombre d'années")
    plt.ylabel("Catégories des souscripteurs")
    plt.yticks([])
    
    # Création de la légende en utilisant des proxies (éléments de la légende sans affichage réel)
    legend_proxies = [plt.Rectangle((0, 0), 1, 1, color=color) for color in custom_colors]
    plt.legend(legend_proxies, categories)
    
    # Afficher le boxplot
    plt.show()
    
    # Créer les groupes pour le boxplot et inverser l'ordre des données grouped_data = df_durée_conserv.groupby('Catégories souscripteurs')['durée conservation'].apply(list) # Créer le boxplot en inversant l'ordre des positions plt.figure(figsize=(8, 6)) boxes = plt.boxplot(grouped_data, vert=False, patch_artist=True) custom_order = ['10 souscriptions et plus', '6 à 10 souscriptions', '3 à 5 souscriptions', '2 souscriptions', '1 souscription'] grouped_data = grouped_data.reindex(custom_order) # Récupérer les étiquettes de catégories categories = grouped_data.index # Couleurs personnalisées pour chaque boîte custom_colors = ['powderblue', 'lightskyblue', 'lightslategray', 'lightsteelblue', 'steelblue'] # Attribution des couleurs aux boîtes for box, color in zip(boxes['boxes'], custom_colors): box.set_facecolor(color) # Titre et étiquette des axes plt.title("Durées moyennes entre interactions sur un contrat par catégories des souscripteurs") plt.xlabel("Nombre d'années") plt.ylabel("Catégories des souscripteurs") plt.yticks([]) # Création de la légende en utilisant des proxies (éléments de la légende sans affichage réel) legend_proxies = [plt.Rectangle((0, 0), 1, 1, color=color) for color in custom_colors] plt.legend(legend_proxies, categories) # Afficher le boxplot plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    import pandas as pd
    import numpy as np
    
    # Compter le nombre de personnes par catégorie de souscripteur
    df_retraitMS = df_durée_conserv['Catégories souscripteurs'].value_counts().to_frame().reset_index()
    
    # Renommer les colonnes
    df_retraitMS.columns = ['Catégories souscripteurs', "Nombre d'individus"]
    
    # Calculer la moyenne, Q1, Q3 et les whiskers de la variable "Durée actionnariat" pour chaque catégorie
    df_stats = df_durée_conserv.groupby('Catégories souscripteurs')['durée conservation'].agg(['median', lambda x: np.percentile(x, 25), lambda x: np.percentile(x, 75), lambda x: np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25))]).reset_index()
    
    # Renommer les colonnes de statistiques
    df_stats.columns = ['Catégories souscripteurs', 'Médiane Durée conservation', 'Q1', 'Q3', 'Upper Whiskers']
    
    # Calculer le nombre d'outliers pour chaque catégorie
    df_outliers = df_durée_conserv.groupby('Catégories souscripteurs')['durée conservation'].apply(lambda x: np.sum((x < np.percentile(x, 25) - 1.5*(np.percentile(x, 75) - np.percentile(x, 25))) | (x > np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25))))).reset_index()
    df_outliers.columns = ['Catégories souscripteurs', 'Nombre d\'outliers']
    
    # Fusionner les DataFrames pour ajouter les statistiques et le nombre d'outliers
    df_retraitMS = pd.merge(df_retraitMS, df_stats, on='Catégories souscripteurs')
    df_retraitMS = pd.merge(df_retraitMS, df_outliers, on='Catégories souscripteurs')
    
    # Afficher le résultat
    df_retraitMS
    
    import pandas as pd import numpy as np # Compter le nombre de personnes par catégorie de souscripteur df_retraitMS = df_durée_conserv['Catégories souscripteurs'].value_counts().to_frame().reset_index() # Renommer les colonnes df_retraitMS.columns = ['Catégories souscripteurs', "Nombre d'individus"] # Calculer la moyenne, Q1, Q3 et les whiskers de la variable "Durée actionnariat" pour chaque catégorie df_stats = df_durée_conserv.groupby('Catégories souscripteurs')['durée conservation'].agg(['median', lambda x: np.percentile(x, 25), lambda x: np.percentile(x, 75), lambda x: np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25))]).reset_index() # Renommer les colonnes de statistiques df_stats.columns = ['Catégories souscripteurs', 'Médiane Durée conservation', 'Q1', 'Q3', 'Upper Whiskers'] # Calculer le nombre d'outliers pour chaque catégorie df_outliers = df_durée_conserv.groupby('Catégories souscripteurs')['durée conservation'].apply(lambda x: np.sum((x < np.percentile(x, 25) - 1.5*(np.percentile(x, 75) - np.percentile(x, 25))) | (x > np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25))))).reset_index() df_outliers.columns = ['Catégories souscripteurs', 'Nombre d\'outliers'] # Fusionner les DataFrames pour ajouter les statistiques et le nombre d'outliers df_retraitMS = pd.merge(df_retraitMS, df_stats, on='Catégories souscripteurs') df_retraitMS = pd.merge(df_retraitMS, df_outliers, on='Catégories souscripteurs') # Afficher le résultat df_retraitMS
    Out[ ]:
    Catégories souscripteurs Nombre d'individus Médiane Durée conservation Q1 Q3 Upper Whiskers Nombre d'outliers
    0 1 souscription 656 6.8 3.30 10.80 22.05 0
    1 2 souscriptions 331 6.3 3.15 9.65 19.40 0
    2 3 à 5 souscriptions 141 6.2 3.00 9.20 18.50 0
    3 6 à 10 souscriptions 49 6.5 3.40 10.50 21.15 0
    4 10 souscriptions et plus 7 5.1 3.10 6.80 12.35 1
    In [ ]:
    Copied!
    # Créer les groupes pour le boxplot et inverser l'ordre des données
    grouped_data = df_durée_conserv.groupby('catégories âge')['durée conservation'].apply(list)
    custom_order = ['60 ans et plus', '40-60 ans', '25-40 ans', '0-25 ans']
    grouped_data = grouped_data.reindex(custom_order)
    # Créer le boxplot en inversant l'ordre des positions
    plt.figure(figsize=(8, 6))
    boxes = plt.boxplot(grouped_data, vert=False, patch_artist=True)
    
    
    # Récupérer les étiquettes de catégories
    categories = grouped_data.index
    
    # Couleurs personnalisées pour chaque boîte
    custom_colors = ['powderblue', 'lightskyblue', 'lightslategray', 'lightsteelblue', 'steelblue']
    
    # Attribution des couleurs aux boîtes
    for box, color in zip(boxes['boxes'], custom_colors):
        box.set_facecolor(color)
    
    # Titre et étiquette des axes
    plt.title("Durées moyennes entre interactions sur un contrat par catégories d'âges")
    plt.xlabel("Nombre d'années")
    plt.ylabel("Catégories d'âges")
    plt.yticks([])
    
    # Création de la légende en utilisant des proxies (éléments de la légende sans affichage réel)
    legend_proxies = [plt.Rectangle((0, 0), 1, 1, color=color) for color in custom_colors]
    plt.legend(legend_proxies, categories)
    
    # Afficher le boxplot
    plt.show()
    
    # Créer les groupes pour le boxplot et inverser l'ordre des données grouped_data = df_durée_conserv.groupby('catégories âge')['durée conservation'].apply(list) custom_order = ['60 ans et plus', '40-60 ans', '25-40 ans', '0-25 ans'] grouped_data = grouped_data.reindex(custom_order) # Créer le boxplot en inversant l'ordre des positions plt.figure(figsize=(8, 6)) boxes = plt.boxplot(grouped_data, vert=False, patch_artist=True) # Récupérer les étiquettes de catégories categories = grouped_data.index # Couleurs personnalisées pour chaque boîte custom_colors = ['powderblue', 'lightskyblue', 'lightslategray', 'lightsteelblue', 'steelblue'] # Attribution des couleurs aux boîtes for box, color in zip(boxes['boxes'], custom_colors): box.set_facecolor(color) # Titre et étiquette des axes plt.title("Durées moyennes entre interactions sur un contrat par catégories d'âges") plt.xlabel("Nombre d'années") plt.ylabel("Catégories d'âges") plt.yticks([]) # Création de la légende en utilisant des proxies (éléments de la légende sans affichage réel) legend_proxies = [plt.Rectangle((0, 0), 1, 1, color=color) for color in custom_colors] plt.legend(legend_proxies, categories) # Afficher le boxplot plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    # Créer les groupes pour le boxplot et inverser l'ordre des données
    
    custom_order = ['0-25 ans', '25-40 ans', '40-60 ans', '60 ans et plus']
    
    grouped_data = grouped_data.reindex(custom_order)
    grouped_data = df_durée_conserv.groupby('catégories âge')['durée conservation'].apply(list)
    grouped_data = grouped_data.reindex(custom_order)
    # Créer le tableau
    df_interactions_age = grouped_data.apply(lambda x: pd.Series({
        'Médiane Durée conservation': np.median(x),
        'Q1': np.percentile(x, 25),
        'Q3': np.percentile(x, 75),
        'Upper Whiskers': np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25)),
        "Nombre d'outliers": np.sum((x < np.percentile(x, 25) - 1.5*(np.percentile(x, 75) - np.percentile(x, 25))) | (x > np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25))))
    })).reset_index()
    df_interactions_age.rename(columns={'catégories âge': 'Catégories d\'âges'}, inplace=True)
    
    df_interactions_age
    
    # Créer les groupes pour le boxplot et inverser l'ordre des données custom_order = ['0-25 ans', '25-40 ans', '40-60 ans', '60 ans et plus'] grouped_data = grouped_data.reindex(custom_order) grouped_data = df_durée_conserv.groupby('catégories âge')['durée conservation'].apply(list) grouped_data = grouped_data.reindex(custom_order) # Créer le tableau df_interactions_age = grouped_data.apply(lambda x: pd.Series({ 'Médiane Durée conservation': np.median(x), 'Q1': np.percentile(x, 25), 'Q3': np.percentile(x, 75), 'Upper Whiskers': np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25)), "Nombre d'outliers": np.sum((x < np.percentile(x, 25) - 1.5*(np.percentile(x, 75) - np.percentile(x, 25))) | (x > np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25)))) })).reset_index() df_interactions_age.rename(columns={'catégories âge': 'Catégories d\'âges'}, inplace=True) df_interactions_age
    Out[ ]:
    Catégories d'âges Médiane Durée conservation Q1 Q3 Upper Whiskers Nombre d'outliers
    0 0-25 ans 6.3 3.40 10.40 20.900 0.0
    1 25-40 ans 6.7 3.15 9.95 20.150 0.0
    2 40-60 ans 6.8 3.40 10.40 20.900 0.0
    3 60 ans et plus 6.5 3.00 9.95 20.375 0.0
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>La tranche des 25-40 ans rachète plus rapidement leurs actions</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    La tranche des 25-40 ans rachète plus rapidement leurs actions

    "))

    La tranche des 25-40 ans rachète plus rapidement leurs actions

    In [ ]:
    Copied!
    # Créer les groupes pour le boxplot et inverser l'ordre des données
    grouped_data = df_durée_conserv.groupby('ancienneté actionnaires')['durée conservation'].apply(list)
    
    # Créer le boxplot en inversant l'ordre des positions
    plt.figure(figsize=(8, 6))
    boxes = plt.boxplot(grouped_data, vert=False, patch_artist=True)
    ordre_categories_ancienneté = ['Nouvel actionnaire depuis 2017 ou plus', 'Nouvel actionnaire entre 2012 à 2017', 'Nouvel actionnaire en 2012 ou moins']
    grouped_data = grouped_data.reindex(ordre_categories_ancienneté)
    
    # Récupérer les étiquettes de catégories
    categories = grouped_data.index
    
    # Calculer les statistiques pour chaque groupe en inversant l'ordre
    medians = [np.median(data) for data in grouped_data]
    q1s = [np.percentile(data, 25) for data in grouped_data]
    q3s = [np.percentile(data, 75) for data in grouped_data]
    upper_whiskers = [q3 + 1.5 * (q3 - q1) for q3, q1 in zip(q3s, q1s)]
    upper_whiskers = np.round(upper_whiskers, 1)  # Arrondir les valeurs à 2 décimales
    num_outliers = [len(box.get_ydata()) for box in boxes['fliers']]
    
    # Couleurs personnalisées pour chaque boîte
    custom_colors = ['powderblue', 'lightskyblue', 'lightslategray', 'lightsteelblue', 'steelblue']
    
    # Attribution des couleurs aux boîtes
    for box, color in zip(boxes['boxes'], custom_colors):
        box.set_facecolor(color)
    
    # Titre et étiquette des axes
    plt.title("Durées moyennes entre interactions sur un contrat par catégories d'ancienneté des actionnaires")
    plt.xlabel("Nombre d'années")
    plt.ylabel("Catégories d'ancienneté")
    plt.yticks([])
    
    # Création de la légende en utilisant des proxies (éléments de la légende sans affichage réel)
    legend_proxies = [plt.Rectangle((0, 0), 1, 1, color=color) for color in custom_colors]
    plt.legend(legend_proxies, categories)
    
    
    # Afficher le boxplot
    plt.show()
    
    # Créer les groupes pour le boxplot et inverser l'ordre des données grouped_data = df_durée_conserv.groupby('ancienneté actionnaires')['durée conservation'].apply(list) # Créer le boxplot en inversant l'ordre des positions plt.figure(figsize=(8, 6)) boxes = plt.boxplot(grouped_data, vert=False, patch_artist=True) ordre_categories_ancienneté = ['Nouvel actionnaire depuis 2017 ou plus', 'Nouvel actionnaire entre 2012 à 2017', 'Nouvel actionnaire en 2012 ou moins'] grouped_data = grouped_data.reindex(ordre_categories_ancienneté) # Récupérer les étiquettes de catégories categories = grouped_data.index # Calculer les statistiques pour chaque groupe en inversant l'ordre medians = [np.median(data) for data in grouped_data] q1s = [np.percentile(data, 25) for data in grouped_data] q3s = [np.percentile(data, 75) for data in grouped_data] upper_whiskers = [q3 + 1.5 * (q3 - q1) for q3, q1 in zip(q3s, q1s)] upper_whiskers = np.round(upper_whiskers, 1) # Arrondir les valeurs à 2 décimales num_outliers = [len(box.get_ydata()) for box in boxes['fliers']] # Couleurs personnalisées pour chaque boîte custom_colors = ['powderblue', 'lightskyblue', 'lightslategray', 'lightsteelblue', 'steelblue'] # Attribution des couleurs aux boîtes for box, color in zip(boxes['boxes'], custom_colors): box.set_facecolor(color) # Titre et étiquette des axes plt.title("Durées moyennes entre interactions sur un contrat par catégories d'ancienneté des actionnaires") plt.xlabel("Nombre d'années") plt.ylabel("Catégories d'ancienneté") plt.yticks([]) # Création de la légende en utilisant des proxies (éléments de la légende sans affichage réel) legend_proxies = [plt.Rectangle((0, 0), 1, 1, color=color) for color in custom_colors] plt.legend(legend_proxies, categories) # Afficher le boxplot plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    custom_order = ['Nouvel actionnaire depuis 2017 ou plus', 'Nouvel actionnaire entre 2012 à 2017', 'Nouvel actionnaire en 2012 ou moins']
    
    # Réorganiser les indices du groupe grouped_data
    grouped_data = grouped_data.reindex(custom_order)
    
    # Créer le tableau
    df_interaction_ancienneté = grouped_data.apply(lambda x: pd.Series({
        'Médiane Durée conservation': np.median(x),
        'Q1': np.percentile(x, 25),
        'Q3': np.percentile(x, 75),
        'Upper Whiskers': np.percentile(x, 75) + 1.5 * (np.percentile(x, 75) - np.percentile(x, 25)),
        "Nombre d'outliers": np.sum((x < np.percentile(x, 25) - 1.5 * (np.percentile(x, 75) - np.percentile(x, 25))) | (x > np.percentile(x, 75) + 1.5 * (np.percentile(x, 75) - np.percentile(x, 25))))
    })).reset_index()
    df_interaction_ancienneté.rename(columns={'ancienneté actionnaires': 'Catégories d\'ancienneté'}, inplace=True)
    
    df_interaction_ancienneté
    
    custom_order = ['Nouvel actionnaire depuis 2017 ou plus', 'Nouvel actionnaire entre 2012 à 2017', 'Nouvel actionnaire en 2012 ou moins'] # Réorganiser les indices du groupe grouped_data grouped_data = grouped_data.reindex(custom_order) # Créer le tableau df_interaction_ancienneté = grouped_data.apply(lambda x: pd.Series({ 'Médiane Durée conservation': np.median(x), 'Q1': np.percentile(x, 25), 'Q3': np.percentile(x, 75), 'Upper Whiskers': np.percentile(x, 75) + 1.5 * (np.percentile(x, 75) - np.percentile(x, 25)), "Nombre d'outliers": np.sum((x < np.percentile(x, 25) - 1.5 * (np.percentile(x, 75) - np.percentile(x, 25))) | (x > np.percentile(x, 75) + 1.5 * (np.percentile(x, 75) - np.percentile(x, 25)))) })).reset_index() df_interaction_ancienneté.rename(columns={'ancienneté actionnaires': 'Catégories d\'ancienneté'}, inplace=True) df_interaction_ancienneté
    Out[ ]:
    Catégories d'ancienneté Médiane Durée conservation Q1 Q3 Upper Whiskers Nombre d'outliers
    0 Nouvel actionnaire depuis 2017 ou plus 7.6 4.00 11.20 22.0 0.0
    1 Nouvel actionnaire entre 2012 à 2017 6.6 3.05 9.75 19.8 0.0
    2 Nouvel actionnaire en 2012 ou moins 5.3 2.50 8.70 18.0 0.0
    In [ ]:
    Copied!
    # Créer les groupes pour le boxplot et inverser l'ordre des données
    grouped_data = df_durée_conserv.groupby('multi-casquette ?')['durée conservation'].apply(list)
    
    # Créer le boxplot en inversant l'ordre des positions
    plt.figure(figsize=(8, 6))
    boxes = plt.boxplot(grouped_data, vert=False, patch_artist=True)
    
    # Récupérer les étiquettes de catégories
    categories = grouped_data.index
    
    # Couleurs personnalisées pour chaque boîte
    custom_colors = ['powderblue', 'lightskyblue', 'lightslategray', 'lightsteelblue', 'steelblue']
    
    # Attribution des couleurs aux boîtes
    for box, color in zip(boxes['boxes'], custom_colors):
        box.set_facecolor(color)
    
    
    # Titre et étiquette des axes
    plt.title("Durées moyennes entre interactions sur un contrat par catégories de multi-engagment")
    plt.xlabel("Nombre d'années")
    plt.ylabel("Catégories de multi-engagement")
    plt.yticks([])
    
    
    # Création de la légende en utilisant des proxies (éléments de la légende sans affichage réel)
    legend_proxies = [plt.Rectangle((0, 0), 1, 1, color=color) for color in custom_colors]
    plt.legend(legend_proxies, categories)
    
    
    # Afficher le boxplot
    plt.show()
    
    # Créer les groupes pour le boxplot et inverser l'ordre des données grouped_data = df_durée_conserv.groupby('multi-casquette ?')['durée conservation'].apply(list) # Créer le boxplot en inversant l'ordre des positions plt.figure(figsize=(8, 6)) boxes = plt.boxplot(grouped_data, vert=False, patch_artist=True) # Récupérer les étiquettes de catégories categories = grouped_data.index # Couleurs personnalisées pour chaque boîte custom_colors = ['powderblue', 'lightskyblue', 'lightslategray', 'lightsteelblue', 'steelblue'] # Attribution des couleurs aux boîtes for box, color in zip(boxes['boxes'], custom_colors): box.set_facecolor(color) # Titre et étiquette des axes plt.title("Durées moyennes entre interactions sur un contrat par catégories de multi-engagment") plt.xlabel("Nombre d'années") plt.ylabel("Catégories de multi-engagement") plt.yticks([]) # Création de la légende en utilisant des proxies (éléments de la légende sans affichage réel) legend_proxies = [plt.Rectangle((0, 0), 1, 1, color=color) for color in custom_colors] plt.legend(legend_proxies, categories) # Afficher le boxplot plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    # Créer le tableau de statistiques
    df_interaction_multicasquette = grouped_data.apply(lambda x: pd.Series({
        'Médiane Durée conservation': np.median(x),
        'Q1': np.percentile(x, 25),
        'Q3': np.percentile(x, 75),
        'Upper Whiskers': np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25)),
        "Nombre d'outliers": np.sum((x < np.percentile(x, 25) - 1.5*(np.percentile(x, 75) - np.percentile(x, 25))) | (x > np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25))))
    })).reset_index()
    df_interaction_multicasquette.rename(columns={'multi-casquette ?': 'Catégories de multi-engagement'}, inplace=True)
    df_interaction_multicasquette = df_interaction_multicasquette.iloc[::-1].reset_index(drop=True)
    df_interaction_multicasquette
    
    # Créer le tableau de statistiques df_interaction_multicasquette = grouped_data.apply(lambda x: pd.Series({ 'Médiane Durée conservation': np.median(x), 'Q1': np.percentile(x, 25), 'Q3': np.percentile(x, 75), 'Upper Whiskers': np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25)), "Nombre d'outliers": np.sum((x < np.percentile(x, 25) - 1.5*(np.percentile(x, 75) - np.percentile(x, 25))) | (x > np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25)))) })).reset_index() df_interaction_multicasquette.rename(columns={'multi-casquette ?': 'Catégories de multi-engagement'}, inplace=True) df_interaction_multicasquette = df_interaction_multicasquette.iloc[::-1].reset_index(drop=True) df_interaction_multicasquette
    Out[ ]:
    Catégories de multi-engagement Médiane Durée conservation Q1 Q3 Upper Whiskers Nombre d'outliers
    0 Triple-engagement 6.7 3.35 10.100 20.2250 0.0
    1 Actionnaire-donateur 6.4 3.40 9.800 19.4000 0.0
    2 Actionnaire-adhérent 6.3 2.70 10.200 21.4500 0.0
    3 Actionnaire uniquement 6.6 3.70 10.825 21.5125 0.0
    In [ ]:
    Copied!
    from IPython.display import display, HTML
    display(HTML("<div style='page-break-before: always;'></div>"))
    
    
    # Afficher un titre centré avec une taille de police plus grande
    display(HTML('<center><h2><u>Retrait partiel ou total des actions sur un contrat ?</u></h2></center>'))
    
    from IPython.display import display, HTML display(HTML("
    ")) # Afficher un titre centré avec une taille de police plus grande display(HTML('

    Retrait partiel ou total des actions sur un contrat ?

    '))

    Retrait partiel ou total des actions sur un contrat ?

    In [ ]:
    Copied!
    df.loc[:, 'multi-souscripteur ?'] = df.duplicated(subset='ID du contact', keep=False)
    df_durée_conserv = df[df["Nature du mouvement"]== "Rachat"]
    
    df.loc[:, 'multi-souscripteur ?'] = df.duplicated(subset='ID du contact', keep=False) df_durée_conserv = df[df["Nature du mouvement"]== "Rachat"]
    In [ ]:
    Copied!
    import matplotlib.pyplot as plt
    
    # Calculer les valeurs et les étiquettes pour le pie chart
    counts = df['retrait complet ou partiel'].value_counts()
    percentages = counts / counts.sum() * 100
    
    # Créer le pie chart
    plt.pie(counts, labels=counts.index, autopct='%1.1f%%', startangle=90)
    plt.title("Retrait complet ou partiel d'actions pour un contrat")
    
    
    
    # Afficher le graphique
    plt.show()
    
    import matplotlib.pyplot as plt # Calculer les valeurs et les étiquettes pour le pie chart counts = df['retrait complet ou partiel'].value_counts() percentages = counts / counts.sum() * 100 # Créer le pie chart plt.pie(counts, labels=counts.index, autopct='%1.1f%%', startangle=90) plt.title("Retrait complet ou partiel d'actions pour un contrat") # Afficher le graphique plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Retrait total ou partiels des actions sur les contrats par multi-souscripteur ?</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Retrait total ou partiels des actions sur les contrats par multi-souscripteur ?

    "))

    Retrait total ou partiels des actions sur les contrats par multi-souscripteur ?

    In [ ]:
    Copied!
    df_retrait_MS = pd.crosstab(index=df_durée_conserv['retrait complet ou partiel'], columns=df_durée_conserv["multi-souscripteur ?"], margins=True, margins_name='Total')
    df_col_percent = df_retrait_MS.copy()
    df_col_percent = df_col_percent.div(df_col_percent.loc['Total']) * 100
    df_col_percent = df_col_percent.round(1)
    df_col_percent.iloc[-1] = df_col_percent.iloc[:-1].sum()  # Ajouter la somme des pourcentages dans la dernière ligne
    df_col_percent = df_col_percent.drop(columns=True)
    df_col_percent
    
    df_retrait_MS = pd.crosstab(index=df_durée_conserv['retrait complet ou partiel'], columns=df_durée_conserv["multi-souscripteur ?"], margins=True, margins_name='Total') df_col_percent = df_retrait_MS.copy() df_col_percent = df_col_percent.div(df_col_percent.loc['Total']) * 100 df_col_percent = df_col_percent.round(1) df_col_percent.iloc[-1] = df_col_percent.iloc[:-1].sum() # Ajouter la somme des pourcentages dans la dernière ligne df_col_percent = df_col_percent.drop(columns=True) df_col_percent
    Out[ ]:
    multi-souscripteur ? False Total
    retrait complet ou partiel
    retrait complet 82.2 83.5
    retrait partiel 17.8 16.5
    Total 100.0 100.0
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Clé de lecture : Lorsqu'ils ont interagi avec un de leurs contrats pour y racheter des actions, les multi-souscripteurs dans 92,7% des cas ont racheté toutes les actions du contrat (retrait complet) et des les 7,3% dans cas restants n'ont pas racheté toutes les actions du contrats (retrait partiel)</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Clé de lecture : Lorsqu'ils ont interagi avec un de leurs contrats pour y racheter des actions, les multi-souscripteurs dans 92,7% des cas ont racheté toutes les actions du contrat (retrait complet) et des les 7,3% dans cas restants n'ont pas racheté toutes les actions du contrats (retrait partiel)

    "))

    Clé de lecture : Lorsqu'ils ont interagi avec un de leurs contrats pour y racheter des actions, les multi-souscripteurs dans 92,7% des cas ont racheté toutes les actions du contrat (retrait complet) et des les 7,3% dans cas restants n'ont pas racheté toutes les actions du contrats (retrait partiel)

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    display(HTML("<div style='page-break-before: always;'></div>"))
    display(HTML("<h2>Part des personnes qui ont re-souscrit la même année après s'être fait remboursé leurs actions rachetées</h2>"))
    
    from IPython.display import display, Markdown, HTML display(HTML("
    ")) display(HTML("

    Part des personnes qui ont re-souscrit la même année après s'être fait remboursé leurs actions rachetées

    "))

    Part des personnes qui ont re-souscrit la même année après s'être fait remboursé leurs actions rachetées

    In [ ]:
    Copied!
    dfretraitrepise = dfretraitrepise[["ID du contact", "Nature du mouvement","Date du Mouvement"]]
    dfretraitrepise = dfretraitrepise[(dfretraitrepise["Nature du mouvement"] == "Souscription") | (dfretraitrepise["Nature du mouvement"] == "Rachat")]
    dfretraitrepise["Date du Mouvement"] = pd.to_datetime(dfretraitrepise["Date du Mouvement"], format='%d/%m/%Y')
    dfretraitrepise["Date du Mouvement"] = dfretraitrepise["Date du Mouvement"].dt.year.astype(int)
    # Créez une liste des années uniques dans la colonne "Date du Mouvement"
    annees_uniques = dfretraitrepise["Date du Mouvement"].unique()
    
    # Créez une liste des natures de mouvement uniques dans la colonne "Nature du mouvement"
    natures_uniques = dfretraitrepise["Nature du mouvement"].unique()
    
    # Créez des colonnes de variables binaires pour chaque année et nature de mouvement
    for annee in annees_uniques:
        for nature in natures_uniques:
            # Créez une nouvelle colonne avec un nom basé sur l'année et la nature du mouvement
            nom_colonne = f"{nature} {annee}"
            
            # Utilisez np.where pour définir la valeur en fonction de la condition
            dfretraitrepise[nom_colonne] = np.where((dfretraitrepise["Date du Mouvement"] == annee) & (dfretraitrepise["Nature du mouvement"] == nature), True, False)
    
    # Réorganisez les colonnes pour placer "ID du contact", "Nature du mouvement" et "Date du Mouvement" au début
    colonnes = ["ID du contact", "Nature du mouvement", "Date du Mouvement"]
    colonnes += sorted([colonne for colonne in dfretraitrepise.columns if colonne not in colonnes])
    
    # Sélectionnez et réorganisez les colonnes dans le DataFrame
    dfretraitrepise = dfretraitrepise[colonnes]
    dfretraitrepise = dfretraitrepise.groupby('ID du contact').max().reset_index()
    dfretraitrepise = dfretraitrepise.drop(columns= ["Nature du mouvement", "Date du Mouvement"])
    dfretraitrepiseretrait = dfretraitrepise.copy()
    # Initialiser une liste vide pour stocker le nombre de reprises après rachat
    nombre_de_reprises = []
    
    # Parcourir les lignes du DataFrame
    for i in range(len(dfretraitrepise)):
        # Initialisez un compteur pour cette ligne
        compteur = 0
        
        # Parcourir les années de 2006 à 2022
        for annee in range(2006, 2023):
            # Vérifier si "Rachat N" = True et "Souscription N+1" = True
            rachat_colonne = f"Rachat {annee}"
            souscription_colonne = f"Souscription {annee + 1}"
            
            if dfretraitrepise[rachat_colonne][i] == True and dfretraitrepise[souscription_colonne][i] == True:
                compteur += 1
        
        # Ajouter le compteur à la liste des nombres de reprises après rachat
        nombre_de_reprises.append(compteur)
    
    # Ajouter la liste des nombres de reprises après rachat comme colonne au DataFrame
    dfretraitrepise["nombre de reprises après rachat"] = nombre_de_reprises
    
    
    # Créer la colonne "a_resouscrit_juste_apres_avoir_racheté" en utilisant la condition
    dfretraitrepise["A resouscrit juste apres avoir racheté"] = dfretraitrepise["nombre de reprises après rachat"] > 0
    dfretraitrepise["A resouscrit juste apres avoir racheté"]  = dfretraitrepise["A resouscrit juste apres avoir racheté"].replace({True: "A re-souscrit la même année apres s'être fait rembourser les actions rachetées", False: "N'a pas re-souscrit la même année apres s'être fait rembourser les actions rachetées"})
    import matplotlib.pyplot as plt
    
    # Compter les occurrences de chaque valeur unique
    value_counts = dfretraitrepise["A resouscrit juste apres avoir racheté"].value_counts()
    
    # Créer un pie chart avec les pourcentages et les valeurs absolues
    plt.figure(figsize=(6, 6))
    patches, texts, autotexts = plt.pie(value_counts, labels=value_counts.index, autopct='%1.1f%%', startangle=30)
    
    # Ajouter les valeurs absolues aux étiquettes
    for i, (label, count) in enumerate(zip(texts, value_counts)):
        label.set_text(f"{label.get_text()} ({count})")
    
    plt.title("")
    plt.axis('equal')  # Assure que le pie chart est un cercle
    
    plt.show()
    
    dfretraitrepise = dfretraitrepise[["ID du contact", "Nature du mouvement","Date du Mouvement"]] dfretraitrepise = dfretraitrepise[(dfretraitrepise["Nature du mouvement"] == "Souscription") | (dfretraitrepise["Nature du mouvement"] == "Rachat")] dfretraitrepise["Date du Mouvement"] = pd.to_datetime(dfretraitrepise["Date du Mouvement"], format='%d/%m/%Y') dfretraitrepise["Date du Mouvement"] = dfretraitrepise["Date du Mouvement"].dt.year.astype(int) # Créez une liste des années uniques dans la colonne "Date du Mouvement" annees_uniques = dfretraitrepise["Date du Mouvement"].unique() # Créez une liste des natures de mouvement uniques dans la colonne "Nature du mouvement" natures_uniques = dfretraitrepise["Nature du mouvement"].unique() # Créez des colonnes de variables binaires pour chaque année et nature de mouvement for annee in annees_uniques: for nature in natures_uniques: # Créez une nouvelle colonne avec un nom basé sur l'année et la nature du mouvement nom_colonne = f"{nature} {annee}" # Utilisez np.where pour définir la valeur en fonction de la condition dfretraitrepise[nom_colonne] = np.where((dfretraitrepise["Date du Mouvement"] == annee) & (dfretraitrepise["Nature du mouvement"] == nature), True, False) # Réorganisez les colonnes pour placer "ID du contact", "Nature du mouvement" et "Date du Mouvement" au début colonnes = ["ID du contact", "Nature du mouvement", "Date du Mouvement"] colonnes += sorted([colonne for colonne in dfretraitrepise.columns if colonne not in colonnes]) # Sélectionnez et réorganisez les colonnes dans le DataFrame dfretraitrepise = dfretraitrepise[colonnes] dfretraitrepise = dfretraitrepise.groupby('ID du contact').max().reset_index() dfretraitrepise = dfretraitrepise.drop(columns= ["Nature du mouvement", "Date du Mouvement"]) dfretraitrepiseretrait = dfretraitrepise.copy() # Initialiser une liste vide pour stocker le nombre de reprises après rachat nombre_de_reprises = [] # Parcourir les lignes du DataFrame for i in range(len(dfretraitrepise)): # Initialisez un compteur pour cette ligne compteur = 0 # Parcourir les années de 2006 à 2022 for annee in range(2006, 2023): # Vérifier si "Rachat N" = True et "Souscription N+1" = True rachat_colonne = f"Rachat {annee}" souscription_colonne = f"Souscription {annee + 1}" if dfretraitrepise[rachat_colonne][i] == True and dfretraitrepise[souscription_colonne][i] == True: compteur += 1 # Ajouter le compteur à la liste des nombres de reprises après rachat nombre_de_reprises.append(compteur) # Ajouter la liste des nombres de reprises après rachat comme colonne au DataFrame dfretraitrepise["nombre de reprises après rachat"] = nombre_de_reprises # Créer la colonne "a_resouscrit_juste_apres_avoir_racheté" en utilisant la condition dfretraitrepise["A resouscrit juste apres avoir racheté"] = dfretraitrepise["nombre de reprises après rachat"] > 0 dfretraitrepise["A resouscrit juste apres avoir racheté"] = dfretraitrepise["A resouscrit juste apres avoir racheté"].replace({True: "A re-souscrit la même année apres s'être fait rembourser les actions rachetées", False: "N'a pas re-souscrit la même année apres s'être fait rembourser les actions rachetées"}) import matplotlib.pyplot as plt # Compter les occurrences de chaque valeur unique value_counts = dfretraitrepise["A resouscrit juste apres avoir racheté"].value_counts() # Créer un pie chart avec les pourcentages et les valeurs absolues plt.figure(figsize=(6, 6)) patches, texts, autotexts = plt.pie(value_counts, labels=value_counts.index, autopct='%1.1f%%', startangle=30) # Ajouter les valeurs absolues aux étiquettes for i, (label, count) in enumerate(zip(texts, value_counts)): label.set_text(f"{label.get_text()} ({count})") plt.title("") plt.axis('equal') # Assure que le pie chart est un cercle plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Clé de lecture : Ici, il s'agit de vérifier, lorsque un actionnaire fait un rachat qui est effectif au 31/12/N s'il a re-souscrit l'année N+1 car se sera fait rembourser ses action le 01/01/N+1</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Clé de lecture : Ici, il s'agit de vérifier, lorsque un actionnaire fait un rachat qui est effectif au 31/12/N s'il a re-souscrit l'année N+1 car se sera fait rembourser ses action le 01/01/N+1

    "))

    Clé de lecture : Ici, il s'agit de vérifier, lorsque un actionnaire fait un rachat qui est effectif au 31/12/N s'il a re-souscrit l'année N+1 car se sera fait rembourser ses action le 01/01/N+1

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Parmi les personnes ayant effectué un rachat ce sont uniquement 4 % qui ont repris une souscription l'année qui suivait le rachat</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Parmi les personnes ayant effectué un rachat ce sont uniquement 4 % qui ont repris une souscription l'année qui suivait le rachat

    "))

    Parmi les personnes ayant effectué un rachat ce sont uniquement 4 % qui ont repris une souscription l'année qui suivait le rachat

    In [ ]:
    Copied!
    # Sélectionner les lignes où il y a au moins un "True" dans les colonnes "Rachat {année}"
    colonnes_rachat = [f"Rachat {annee}" for annee in range(2006, 2024)]
    dfretraitrepiseretrait_selection = dfretraitrepiseretrait[dfretraitrepiseretrait[colonnes_rachat].any(axis=1)]
    ## Initialiser une liste vide pour stocker le nombre de reprises après rachat
    nombre_de_reprises = []
    
    # Parcourir les lignes du DataFrame avec iterrows()
    for index, row in dfretraitrepiseretrait_selection.iterrows():
        # Initialisez un compteur pour cette ligne
        compteur = 0
        
        # Parcourir les années de 2006 à 2022
        for annee in range(2006, 2023):
            # Vérifier si "Rachat N" = True et "Souscription N+1" = True
            rachat_colonne = f"Rachat {annee}"
            souscription_colonne = f"Souscription {annee + 1}"
            
            if row[rachat_colonne] == True and row[souscription_colonne] == True:
                compteur += 1
        
        # Ajouter le compteur à la liste des nombres de reprises après rachat
        nombre_de_reprises.append(compteur)
    
    # Ajouter la liste des nombres de reprises après rachat comme colonne au DataFrame
    dfretraitrepiseretrait_selection["nombre de reprises après rachat"] = nombre_de_reprises
    
    
    # Créer la colonne "a_resouscrit_juste_apres_avoir_racheté" en utilisant la condition
    dfretraitrepiseretrait_selection["A resouscrit juste apres avoir racheté"] = dfretraitrepiseretrait_selection["nombre de reprises après rachat"] > 0
    dfretraitrepiseretrait_selection["A resouscrit juste apres avoir racheté"]  = dfretraitrepiseretrait_selection["A resouscrit juste apres avoir racheté"].replace({True: "A re-souscrit la même année apres s'être fait rembourser les actions rachetées", False: "N'a pas re-souscrit la même année apres s'être fait rembourser les actions rachetées"})
    import matplotlib.pyplot as plt
    
    # Compter les occurrences de chaque valeur unique
    value_counts = dfretraitrepiseretrait_selection["A resouscrit juste apres avoir racheté"].value_counts()
    
    # Créer un pie chart avec les pourcentages et les valeurs absolues
    plt.figure(figsize=(6, 6))
    patches, texts, autotexts = plt.pie(value_counts, labels=value_counts.index, autopct='%1.1f%%', startangle=30)
    
    # Ajouter les valeurs absolues aux étiquettes
    for i, (label, count) in enumerate(zip(texts, value_counts)):
        label.set_text(f"{label.get_text()} ({count})")
    
    plt.title("")
    plt.axis('equal')  # Assure que le pie chart est un cercle
    
    plt.show()
    
    # Sélectionner les lignes où il y a au moins un "True" dans les colonnes "Rachat {année}" colonnes_rachat = [f"Rachat {annee}" for annee in range(2006, 2024)] dfretraitrepiseretrait_selection = dfretraitrepiseretrait[dfretraitrepiseretrait[colonnes_rachat].any(axis=1)] ## Initialiser une liste vide pour stocker le nombre de reprises après rachat nombre_de_reprises = [] # Parcourir les lignes du DataFrame avec iterrows() for index, row in dfretraitrepiseretrait_selection.iterrows(): # Initialisez un compteur pour cette ligne compteur = 0 # Parcourir les années de 2006 à 2022 for annee in range(2006, 2023): # Vérifier si "Rachat N" = True et "Souscription N+1" = True rachat_colonne = f"Rachat {annee}" souscription_colonne = f"Souscription {annee + 1}" if row[rachat_colonne] == True and row[souscription_colonne] == True: compteur += 1 # Ajouter le compteur à la liste des nombres de reprises après rachat nombre_de_reprises.append(compteur) # Ajouter la liste des nombres de reprises après rachat comme colonne au DataFrame dfretraitrepiseretrait_selection["nombre de reprises après rachat"] = nombre_de_reprises # Créer la colonne "a_resouscrit_juste_apres_avoir_racheté" en utilisant la condition dfretraitrepiseretrait_selection["A resouscrit juste apres avoir racheté"] = dfretraitrepiseretrait_selection["nombre de reprises après rachat"] > 0 dfretraitrepiseretrait_selection["A resouscrit juste apres avoir racheté"] = dfretraitrepiseretrait_selection["A resouscrit juste apres avoir racheté"].replace({True: "A re-souscrit la même année apres s'être fait rembourser les actions rachetées", False: "N'a pas re-souscrit la même année apres s'être fait rembourser les actions rachetées"}) import matplotlib.pyplot as plt # Compter les occurrences de chaque valeur unique value_counts = dfretraitrepiseretrait_selection["A resouscrit juste apres avoir racheté"].value_counts() # Créer un pie chart avec les pourcentages et les valeurs absolues plt.figure(figsize=(6, 6)) patches, texts, autotexts = plt.pie(value_counts, labels=value_counts.index, autopct='%1.1f%%', startangle=30) # Ajouter les valeurs absolues aux étiquettes for i, (label, count) in enumerate(zip(texts, value_counts)): label.set_text(f"{label.get_text()} ({count})") plt.title("") plt.axis('equal') # Assure que le pie chart est un cercle plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    
    display(HTML("<h3>Parmi les peronnes qui ont re-souscrit la même année après s'être fait rembourser leurs actions rachetées, combien de fois l'ont ils fait au cours de leur parcours d'actionnaires</h3>"))
    
    from IPython.display import display, Markdown, HTML display(HTML("

    Parmi les peronnes qui ont re-souscrit la même année après s'être fait rembourser leurs actions rachetées, combien de fois l'ont ils fait au cours de leur parcours d'actionnaires

    "))

    Parmi les peronnes qui ont re-souscrit la même année après s'être fait rembourser leurs actions rachetées, combien de fois l'ont ils fait au cours de leur parcours d'actionnaires

    In [ ]:
    Copied!
    dfretraitrepisetrue = dfretraitrepise[dfretraitrepise["nombre de reprises après rachat"] > 0]
    import matplotlib.pyplot as plt
    
    # Compter les occurrences de chaque valeur unique
    value_counts = dfretraitrepisetrue["nombre de reprises après rachat"].value_counts()
    
    # Créer un pie chart avec les pourcentages et les valeurs absolues
    plt.figure(figsize=(6, 6))
    patches, texts, autotexts = plt.pie(value_counts, labels=value_counts.index, autopct='%1.1f%%', startangle=30)
    
    # Ajouter les valeurs absolues aux étiquettes
    for i, (label, count) in enumerate(zip(texts, value_counts)):
        label.set_text(f"{label.get_text()} ({count})")
    
    plt.title("")
    plt.axis('equal')  # Assure que le pie chart est un cercle
    
    plt.show()
    
    dfretraitrepisetrue = dfretraitrepise[dfretraitrepise["nombre de reprises après rachat"] > 0] import matplotlib.pyplot as plt # Compter les occurrences de chaque valeur unique value_counts = dfretraitrepisetrue["nombre de reprises après rachat"].value_counts() # Créer un pie chart avec les pourcentages et les valeurs absolues plt.figure(figsize=(6, 6)) patches, texts, autotexts = plt.pie(value_counts, labels=value_counts.index, autopct='%1.1f%%', startangle=30) # Ajouter les valeurs absolues aux étiquettes for i, (label, count) in enumerate(zip(texts, value_counts)): label.set_text(f"{label.get_text()} ({count})") plt.title("") plt.axis('equal') # Assure que le pie chart est un cercle plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Clé de lecture : Parmi les 0,3% des actionnaires qui ont re-souscrit l'année d'après leur rachat effectif d'ation, il y en a qui l'ont fait plusieurs fois, la majorité la fait qu'une fois</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Clé de lecture : Parmi les 0,3% des actionnaires qui ont re-souscrit l'année d'après leur rachat effectif d'ation, il y en a qui l'ont fait plusieurs fois, la majorité la fait qu'une fois

    "))

    Clé de lecture : Parmi les 0,3% des actionnaires qui ont re-souscrit l'année d'après leur rachat effectif d'ation, il y en a qui l'ont fait plusieurs fois, la majorité la fait qu'une fois

    In [ ]:
    Copied!
    from IPython.display import display, HTML
    display(HTML("<div style='page-break-before: always;'></div>"))
    
    
    # Afficher un titre centré avec une taille de police plus grande
    display(HTML('<center><h2><u>Retrait définitif ou retrait partiel</u></h2></center>'))
    
    from IPython.display import display, HTML display(HTML("
    ")) # Afficher un titre centré avec une taille de police plus grande display(HTML('

    Retrait définitif ou retrait partiel

    '))

    Retrait définitif ou retrait partiel

    In [ ]:
    Copied!
    df['Nombre de souscriptions'] = df['ID du contact'].map(df2['ID du contact'].value_counts())
    conditions = [
         (df['Nombre de souscriptions'] < 2),
         (df['Nombre de souscriptions'] <3),
         (df['Nombre de souscriptions'] <=5),
         (df['Nombre de souscriptions'] <=10)
    ]
    
    choices = ['1 souscription', "2 souscriptions" , "3 à 5 souscriptions","6 à 10 souscriptions"]
    
    df['Catégories souscripteurs'] = np.select(conditions, choices, default='10 souscriptions et plus')
    
    df['Nombre de souscriptions'] = df['ID du contact'].map(df2['ID du contact'].value_counts()) conditions = [ (df['Nombre de souscriptions'] < 2), (df['Nombre de souscriptions'] <3), (df['Nombre de souscriptions'] <=5), (df['Nombre de souscriptions'] <=10) ] choices = ['1 souscription', "2 souscriptions" , "3 à 5 souscriptions","6 à 10 souscriptions"] df['Catégories souscripteurs'] = np.select(conditions, choices, default='10 souscriptions et plus')
    In [ ]:
    Copied!
    import pandas as pd
    
    # Créer une fonction pour vérifier les conditions
    def is_retrait_definitif(row):
        same_contact_rows = df[df['ID du contact'] == row['ID du contact']]
        later_rows = same_contact_rows[pd.to_datetime(same_contact_rows['Actions - Date de fin'], format="%d/%m/%Y") > pd.to_datetime(row['Date du Mouvement'])]
        return (row['Nature du mouvement'] == 'Rachat' and
                row['retrait complet ou partiel'] == 'retrait complet' and
                later_rows.empty)
    
    # Appliquer la fonction pour créer la variable conditionnelle
    df['nature du retrait'] = df.apply(is_retrait_definitif, axis=1).map({True: 'retrait définitif', False: 'retrait partiel'})
    
    import pandas as pd # Créer une fonction pour vérifier les conditions def is_retrait_definitif(row): same_contact_rows = df[df['ID du contact'] == row['ID du contact']] later_rows = same_contact_rows[pd.to_datetime(same_contact_rows['Actions - Date de fin'], format="%d/%m/%Y") > pd.to_datetime(row['Date du Mouvement'])] return (row['Nature du mouvement'] == 'Rachat' and row['retrait complet ou partiel'] == 'retrait complet' and later_rows.empty) # Appliquer la fonction pour créer la variable conditionnelle df['nature du retrait'] = df.apply(is_retrait_definitif, axis=1).map({True: 'retrait définitif', False: 'retrait partiel'})
    In [ ]:
    Copied!
    df_retrait = df[df['Nature du mouvement'] == "Rachat"]
    df_retraitcount = df_retrait['nature du retrait'].value_counts().sort_index().to_frame()
    df_retraitcount.columns = ['Nombre d\'individus']
    df_retraitcount['Pourcentage'] = df_retraitcount['Nombre d\'individus'].div(df_retraitcount['Nombre d\'individus'].sum()) * 100
    df_retraitcount
    
    df_retrait = df[df['Nature du mouvement'] == "Rachat"] df_retraitcount = df_retrait['nature du retrait'].value_counts().sort_index().to_frame() df_retraitcount.columns = ['Nombre d\'individus'] df_retraitcount['Pourcentage'] = df_retraitcount['Nombre d\'individus'].div(df_retraitcount['Nombre d\'individus'].sum()) * 100 df_retraitcount
    Out[ ]:
    Nombre d'individus Pourcentage
    nature du retrait
    retrait définitif 818 29.562703
    retrait partiel 1949 70.437297
    In [ ]:
    Copied!
    import matplotlib.pyplot as plt
    
    # Extraire les données du DataFrame
    labels = df_retraitcount.index
    sizes = df_retraitcount['Pourcentage']
    
    # Créer le pie chart
    plt.figure(figsize=(8, 6))
    plt.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=90)
    
    # Ajouter un titre
    plt.title("Répartition des types de retrait")
    
    # Afficher le pie chart
    plt.show()
    
    import matplotlib.pyplot as plt # Extraire les données du DataFrame labels = df_retraitcount.index sizes = df_retraitcount['Pourcentage'] # Créer le pie chart plt.figure(figsize=(8, 6)) plt.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=90) # Ajouter un titre plt.title("Répartition des types de retrait") # Afficher le pie chart plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Clé de lecture : Lorsque les souscripteurs ont interagi avec un de leurs contrats pour y racheter TOUTES SES ACTIONS, dans 66,3 % des cas il s'agissait de leur dernier contrat actif. Ainsi lorsque des contrats sont totalement vidés de leurs actions, dans 66% des cas cela met fin à l'activité d'actionnaire d'une personne (ce sont des ex-actionnaires)</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Clé de lecture : Lorsque les souscripteurs ont interagi avec un de leurs contrats pour y racheter TOUTES SES ACTIONS, dans 66,3 % des cas il s'agissait de leur dernier contrat actif. Ainsi lorsque des contrats sont totalement vidés de leurs actions, dans 66% des cas cela met fin à l'activité d'actionnaire d'une personne (ce sont des ex-actionnaires)

    "))

    Clé de lecture : Lorsque les souscripteurs ont interagi avec un de leurs contrats pour y racheter TOUTES SES ACTIONS, dans 66,3 % des cas il s'agissait de leur dernier contrat actif. Ainsi lorsque des contrats sont totalement vidés de leurs actions, dans 66% des cas cela met fin à l'activité d'actionnaire d'une personne (ce sont des ex-actionnaires)

    In [ ]:
    Copied!
    df_retraitdef = df[df["nature du retrait"] == "retrait définitif"]
    df_retraitdef['RFM-Date Première Souscription'] = pd.to_datetime(df_retraitdef['RFM-Date Première Souscription'], format="%Y-%m-%d")
    df_retraitdef["Durée actionnariat"] = df_retraitdef['Date du Mouvement'] - df_retraitdef["RFM-Date Première Souscription"]
    
    df_retraitdef = df[df["nature du retrait"] == "retrait définitif"] df_retraitdef['RFM-Date Première Souscription'] = pd.to_datetime(df_retraitdef['RFM-Date Première Souscription'], format="%Y-%m-%d") df_retraitdef["Durée actionnariat"] = df_retraitdef['Date du Mouvement'] - df_retraitdef["RFM-Date Première Souscription"]
    In [ ]:
    Copied!
    import matplotlib.pyplot as plt
    import numpy as np
    
    
    # Supprimer les lignes contenant des NaN dans la colonne "Durée actionnariat"
    df_retraitdef = df_retraitdef.dropna(subset=["Durée actionnariat"])
    
    # Réinitialiser l'index après la suppression des lignes
    df_retraitdef = df_retraitdef.reset_index(drop=True)
    
    
    # Diviser par un an en utilisant timedelta
    df_retraitdef["Durée actionnariat"] = df_retraitdef["Durée actionnariat"] / pd.to_timedelta(365, unit='D')
    df_retraitdef["Durée actionnariat"] = df_retraitdef["Durée actionnariat"].round(1)
    
    # Calculer la médiane, Q1 et Q3
    median = np.median(df_retraitdef["Durée actionnariat"])
    q1 = np.percentile(df_retraitdef["Durée actionnariat"], 25)
    q3 = np.percentile(df_retraitdef["Durée actionnariat"], 75)
    
    # Calculer les limites inférieures et supérieures des whiskers
    iqr = q3 - q1
    lower_whisker = q1 - 1.5 * iqr
    upper_whisker = q3 + 1.5 * iqr
    upper_whisker = upper_whisker.round(1)
    
    # Créer le box plot horizontalement
    plt.figure(figsize=(8, 6))
    plt.boxplot(df_retraitdef["Durée actionnariat"], vert=False)
    
    # Calculer le nombre d'outliers
    whiskers = plt.boxplot(df_retraitdef["Durée actionnariat"], vert=False)['fliers']
    num_outliers = len(whiskers[0].get_data()[0])
    
    # Ajouter les valeurs de la médiane, Q1, Q3, limites des whiskers au graphique
    plt.text(0.02, 0.9, f"Médiane: {median}", transform=plt.gca().transAxes)
    plt.text(0.02, 0.8, f"Q1: {q1}", transform=plt.gca().transAxes)
    plt.text(0.02, 0.7, f"Q3: {q3}", transform=plt.gca().transAxes)
    plt.text(0.5, 0.8, f"borne supérieur du boxplot: {upper_whisker}", transform=plt.gca().transAxes)
    plt.text(0.5, 0.9, f"Outliers: {num_outliers}", transform=plt.gca().transAxes)
    
    # Titre et étiquette de l'axe y
    plt.title("Durée de la période d'actionnariat de la premiere souscription au retrait complet d'actions")
    plt.xlabel("Nombre d'années")
    plt.ylabel("")
    
    # Afficher le box plot
    plt.show()
    
    import matplotlib.pyplot as plt import numpy as np # Supprimer les lignes contenant des NaN dans la colonne "Durée actionnariat" df_retraitdef = df_retraitdef.dropna(subset=["Durée actionnariat"]) # Réinitialiser l'index après la suppression des lignes df_retraitdef = df_retraitdef.reset_index(drop=True) # Diviser par un an en utilisant timedelta df_retraitdef["Durée actionnariat"] = df_retraitdef["Durée actionnariat"] / pd.to_timedelta(365, unit='D') df_retraitdef["Durée actionnariat"] = df_retraitdef["Durée actionnariat"].round(1) # Calculer la médiane, Q1 et Q3 median = np.median(df_retraitdef["Durée actionnariat"]) q1 = np.percentile(df_retraitdef["Durée actionnariat"], 25) q3 = np.percentile(df_retraitdef["Durée actionnariat"], 75) # Calculer les limites inférieures et supérieures des whiskers iqr = q3 - q1 lower_whisker = q1 - 1.5 * iqr upper_whisker = q3 + 1.5 * iqr upper_whisker = upper_whisker.round(1) # Créer le box plot horizontalement plt.figure(figsize=(8, 6)) plt.boxplot(df_retraitdef["Durée actionnariat"], vert=False) # Calculer le nombre d'outliers whiskers = plt.boxplot(df_retraitdef["Durée actionnariat"], vert=False)['fliers'] num_outliers = len(whiskers[0].get_data()[0]) # Ajouter les valeurs de la médiane, Q1, Q3, limites des whiskers au graphique plt.text(0.02, 0.9, f"Médiane: {median}", transform=plt.gca().transAxes) plt.text(0.02, 0.8, f"Q1: {q1}", transform=plt.gca().transAxes) plt.text(0.02, 0.7, f"Q3: {q3}", transform=plt.gca().transAxes) plt.text(0.5, 0.8, f"borne supérieur du boxplot: {upper_whisker}", transform=plt.gca().transAxes) plt.text(0.5, 0.9, f"Outliers: {num_outliers}", transform=plt.gca().transAxes) # Titre et étiquette de l'axe y plt.title("Durée de la période d'actionnariat de la premiere souscription au retrait complet d'actions") plt.xlabel("Nombre d'années") plt.ylabel("") # Afficher le box plot plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Clé de lecture : Depuis la date de leur entrée dans l'actionnariat, 50 % des souscripteurs attendent 7,7 ans ou moins avant de ne plus être actionnaire. 25 % attendent 5,8 ans ou moins et 25 % attendent 10 ans ou plus soit 75 % qui ont une durée de vie d'actionnaire de moins de 10 ans, (parmi ceux qui ont quitté l'actionnariat). IL y a 0 personnes qui ont un comportement statistiquement ''hors normes''</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Clé de lecture : Depuis la date de leur entrée dans l'actionnariat, 50 % des souscripteurs attendent 7,7 ans ou moins avant de ne plus être actionnaire. 25 % attendent 5,8 ans ou moins et 25 % attendent 10 ans ou plus soit 75 % qui ont une durée de vie d'actionnaire de moins de 10 ans, (parmi ceux qui ont quitté l'actionnariat). IL y a 0 personnes qui ont un comportement statistiquement ''hors normes''

    "))

    Clé de lecture : Depuis la date de leur entrée dans l'actionnariat, 50 % des souscripteurs attendent 7,7 ans ou moins avant de ne plus être actionnaire. 25 % attendent 5,8 ans ou moins et 25 % attendent 10 ans ou plus soit 75 % qui ont une durée de vie d'actionnaire de moins de 10 ans, (parmi ceux qui ont quitté l'actionnariat). IL y a 0 personnes qui ont un comportement statistiquement ''hors normes''

    In [ ]:
    Copied!
    import numpy as np
    import matplotlib.pyplot as plt
    
    # Créer les groupes pour le boxplot et inverser l'ordre des données
    grouped_data = df_retraitdef.groupby('Catégories souscripteurs')['Durée actionnariat'].apply(list)
    custom_order = [ '1 souscription','2 souscriptions', '3 à 5 souscriptions', '6 à 10 souscriptions', '10 souscriptions et plus']
    grouped_data = grouped_data.reindex(custom_order)
    
    
    
    # Créer le boxplot en inversant l'ordre des positions
    plt.figure(figsize=(8, 6))
    boxes = plt.boxplot(grouped_data, vert=False, patch_artist=True)
    
    custom_order = grouped_data.index
    
    # Récupérer les étiquettes de catégories
    categories = custom_order
    # Couleurs personnalisées pour chaque boîte
    custom_colors = ['powderblue', 'lightskyblue', 'lightslategray', 'lightsteelblue', 'steelblue']
    
    # Attribution des couleurs aux boîtes
    for box, color in zip(boxes['boxes'], custom_colors):
        box.set_facecolor(color)
    
    # Titre et étiquette des axes
    plt.title("Durée de la période d'actionnariat de la première souscription au retrait complet d'actions par catégories de souscripteurs")
    plt.xlabel("Nombre d'années")
    plt.ylabel("Catégories des souscripteurs")
    plt.yticks([])
    
    # Création de la légende en utilisant des proxies (éléments de la légende sans affichage réel)
    legend_proxies = [plt.Rectangle((0, 0), 1, 1, color=color) for color in custom_colors]
    plt.legend(legend_proxies, categories)
    
    # Afficher le boxplot
    plt.show()
    
    import numpy as np import matplotlib.pyplot as plt # Créer les groupes pour le boxplot et inverser l'ordre des données grouped_data = df_retraitdef.groupby('Catégories souscripteurs')['Durée actionnariat'].apply(list) custom_order = [ '1 souscription','2 souscriptions', '3 à 5 souscriptions', '6 à 10 souscriptions', '10 souscriptions et plus'] grouped_data = grouped_data.reindex(custom_order) # Créer le boxplot en inversant l'ordre des positions plt.figure(figsize=(8, 6)) boxes = plt.boxplot(grouped_data, vert=False, patch_artist=True) custom_order = grouped_data.index # Récupérer les étiquettes de catégories categories = custom_order # Couleurs personnalisées pour chaque boîte custom_colors = ['powderblue', 'lightskyblue', 'lightslategray', 'lightsteelblue', 'steelblue'] # Attribution des couleurs aux boîtes for box, color in zip(boxes['boxes'], custom_colors): box.set_facecolor(color) # Titre et étiquette des axes plt.title("Durée de la période d'actionnariat de la première souscription au retrait complet d'actions par catégories de souscripteurs") plt.xlabel("Nombre d'années") plt.ylabel("Catégories des souscripteurs") plt.yticks([]) # Création de la légende en utilisant des proxies (éléments de la légende sans affichage réel) legend_proxies = [plt.Rectangle((0, 0), 1, 1, color=color) for color in custom_colors] plt.legend(legend_proxies, categories) # Afficher le boxplot plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    import pandas as pd
    import numpy as np
    
    # Compter le nombre de personnes par catégorie de souscripteur
    df_retraitMS = df_retraitdef['Catégories souscripteurs'].value_counts().to_frame().reset_index()
    
    # Renommer les colonnes
    df_retraitMS.columns = ['Catégories souscripteurs', "Nombre d'individus"]
    
    # Calculer la moyenne, Q1, Q3 et les whiskers de la variable "Durée actionnariat" pour chaque catégorie
    df_stats = df_retraitdef.groupby('Catégories souscripteurs')['Durée actionnariat'].agg(['median', lambda x: np.percentile(x, 25), lambda x: np.percentile(x, 75), lambda x: np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25))]).reset_index()
    
    # Renommer les colonnes de statistiques
    df_stats.columns = ['Catégories souscripteurs', 'Médiane Durée actionnariat', 'Q1', 'Q3', 'Upper Whiskers']
    
    # Calculer le nombre d'outliers pour chaque catégorie
    df_outliers = df_retraitdef.groupby('Catégories souscripteurs')['Durée actionnariat'].apply(lambda x: np.sum((x < np.percentile(x, 25) - 1.5*(np.percentile(x, 75) - np.percentile(x, 25))) | (x > np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25))))).reset_index()
    df_outliers.columns = ['Catégories souscripteurs', 'Nombre d\'outliers']
    
    # Fusionner les DataFrames pour ajouter les statistiques et le nombre d'outliers
    df_retraitMS = pd.merge(df_retraitMS, df_stats, on='Catégories souscripteurs')
    df_retraitMS = pd.merge(df_retraitMS, df_outliers, on='Catégories souscripteurs')
    
    # Classer le tableau par ordre croissant des médianes
    df_retraitMS = df_retraitMS.sort_values(by='Médiane Durée actionnariat')
    ordre_categories_souscripteurs = ['1 souscription', '2 souscriptions', '3 à 5 souscriptions', '6 à 10 souscriptions', '10 souscriptions et plus']
    
    # Ajouter une colonne pour définir l'ordre souhaité
    df_retraitMS['ordre'] = df_retraitMS['Catégories souscripteurs'].apply(lambda x: ordre_categories_souscripteurs.index(x))
    
    # Trier le DataFrame en fonction de la colonne "ordre"
    df_retraitMS = df_retraitMS.sort_values('ordre')
    
    # Supprimer la colonne "ordre"
    df_retraitMS = df_retraitMS.drop('ordre', axis=1)
    
    # Réinitialiser les index
    df_retraitMS.reset_index(drop=True, inplace=True)
    
    df_retraitMS
    
    import pandas as pd import numpy as np # Compter le nombre de personnes par catégorie de souscripteur df_retraitMS = df_retraitdef['Catégories souscripteurs'].value_counts().to_frame().reset_index() # Renommer les colonnes df_retraitMS.columns = ['Catégories souscripteurs', "Nombre d'individus"] # Calculer la moyenne, Q1, Q3 et les whiskers de la variable "Durée actionnariat" pour chaque catégorie df_stats = df_retraitdef.groupby('Catégories souscripteurs')['Durée actionnariat'].agg(['median', lambda x: np.percentile(x, 25), lambda x: np.percentile(x, 75), lambda x: np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25))]).reset_index() # Renommer les colonnes de statistiques df_stats.columns = ['Catégories souscripteurs', 'Médiane Durée actionnariat', 'Q1', 'Q3', 'Upper Whiskers'] # Calculer le nombre d'outliers pour chaque catégorie df_outliers = df_retraitdef.groupby('Catégories souscripteurs')['Durée actionnariat'].apply(lambda x: np.sum((x < np.percentile(x, 25) - 1.5*(np.percentile(x, 75) - np.percentile(x, 25))) | (x > np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25))))).reset_index() df_outliers.columns = ['Catégories souscripteurs', 'Nombre d\'outliers'] # Fusionner les DataFrames pour ajouter les statistiques et le nombre d'outliers df_retraitMS = pd.merge(df_retraitMS, df_stats, on='Catégories souscripteurs') df_retraitMS = pd.merge(df_retraitMS, df_outliers, on='Catégories souscripteurs') # Classer le tableau par ordre croissant des médianes df_retraitMS = df_retraitMS.sort_values(by='Médiane Durée actionnariat') ordre_categories_souscripteurs = ['1 souscription', '2 souscriptions', '3 à 5 souscriptions', '6 à 10 souscriptions', '10 souscriptions et plus'] # Ajouter une colonne pour définir l'ordre souhaité df_retraitMS['ordre'] = df_retraitMS['Catégories souscripteurs'].apply(lambda x: ordre_categories_souscripteurs.index(x)) # Trier le DataFrame en fonction de la colonne "ordre" df_retraitMS = df_retraitMS.sort_values('ordre') # Supprimer la colonne "ordre" df_retraitMS = df_retraitMS.drop('ordre', axis=1) # Réinitialiser les index df_retraitMS.reset_index(drop=True, inplace=True) df_retraitMS
    Out[ ]:
    Catégories souscripteurs Nombre d'individus Médiane Durée actionnariat Q1 Q3 Upper Whiskers Nombre d'outliers
    0 1 souscription 84 7.4 5.175 10.45 18.3625 0
    1 2 souscriptions 7 6.8 6.250 7.50 9.3750 2
    2 10 souscriptions et plus 727 3.7 1.550 7.20 15.6750 3
    In [ ]:
    Copied!
    import numpy as np
    import matplotlib.pyplot as plt
    
    # Créer les groupes pour le boxplot et inverser l'ordre des données
    grouped_data = df_retraitdef.groupby('ancienneté actionnaires')['Durée actionnariat'].apply(list)
    ordre_categories_ancienneté = ['Nouvel actionnaire depuis 2017 ou plus', 'Nouvel actionnaire entre 2012 à 2017', 'Nouvel actionnaire en 2012 ou moins']
    grouped_data = grouped_data.reindex(ordre_categories_ancienneté)
    
    # Créer le boxplot en inversant l'ordre des positions
    plt.figure(figsize=(8, 6))
    boxes = plt.boxplot(grouped_data, vert=False, patch_artist=True)
    
    custom_order = grouped_data.index
    
    # Récupérer les étiquettes de catégories
    categories = custom_order
    # Couleurs personnalisées pour chaque boîte
    custom_colors = ['powderblue', 'lightskyblue', 'lightslategray', 'lightsteelblue', 'steelblue']
    
    # Attribution des couleurs aux boîtes
    for box, color in zip(boxes['boxes'], custom_colors):
        box.set_facecolor(color)
    
    # Titre et étiquette des axes
    plt.title("Durée de la période d'actionnariat de la premiere souscription au retrait complet d'actions par catégories d'ancienneté des actionnaires")
    plt.xlabel("Nombre d'années")
    plt.ylabel("Catégories d'ancienneté")
    plt.yticks([])
    
    # Création de la légende en utilisant des proxies (éléments de la légende sans affichage réel)
    legend_proxies = [plt.Rectangle((0, 0), 1, 1, color=color) for color in custom_colors]
    plt.legend(legend_proxies, categories)
    
    # Afficher le boxplot
    plt.show()
    
    import numpy as np import matplotlib.pyplot as plt # Créer les groupes pour le boxplot et inverser l'ordre des données grouped_data = df_retraitdef.groupby('ancienneté actionnaires')['Durée actionnariat'].apply(list) ordre_categories_ancienneté = ['Nouvel actionnaire depuis 2017 ou plus', 'Nouvel actionnaire entre 2012 à 2017', 'Nouvel actionnaire en 2012 ou moins'] grouped_data = grouped_data.reindex(ordre_categories_ancienneté) # Créer le boxplot en inversant l'ordre des positions plt.figure(figsize=(8, 6)) boxes = plt.boxplot(grouped_data, vert=False, patch_artist=True) custom_order = grouped_data.index # Récupérer les étiquettes de catégories categories = custom_order # Couleurs personnalisées pour chaque boîte custom_colors = ['powderblue', 'lightskyblue', 'lightslategray', 'lightsteelblue', 'steelblue'] # Attribution des couleurs aux boîtes for box, color in zip(boxes['boxes'], custom_colors): box.set_facecolor(color) # Titre et étiquette des axes plt.title("Durée de la période d'actionnariat de la premiere souscription au retrait complet d'actions par catégories d'ancienneté des actionnaires") plt.xlabel("Nombre d'années") plt.ylabel("Catégories d'ancienneté") plt.yticks([]) # Création de la légende en utilisant des proxies (éléments de la légende sans affichage réel) legend_proxies = [plt.Rectangle((0, 0), 1, 1, color=color) for color in custom_colors] plt.legend(legend_proxies, categories) # Afficher le boxplot plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    # Créer le tableau de statistiques
    df_stats = grouped_data.apply(lambda x: pd.Series({
        'Médiane Durée actionnariat': np.median(x),
        'Q1': np.percentile(x, 25),
        'Q3': np.percentile(x, 75),
        'Upper Whiskers': np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25)),
        "Nombre d'outliers": np.sum((x < np.percentile(x, 25) - 1.5*(np.percentile(x, 75) - np.percentile(x, 25))) | (x > np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25))))
    })).reset_index()
    df_stats.rename(columns={'ancienneté actionnaires': 'Catégories d\'ancienneté'}, inplace=True)
    df_stats = df_stats.iloc[::-1].reset_index(drop=True)
    df_stats
    
    # Créer le tableau de statistiques df_stats = grouped_data.apply(lambda x: pd.Series({ 'Médiane Durée actionnariat': np.median(x), 'Q1': np.percentile(x, 25), 'Q3': np.percentile(x, 75), 'Upper Whiskers': np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25)), "Nombre d'outliers": np.sum((x < np.percentile(x, 25) - 1.5*(np.percentile(x, 75) - np.percentile(x, 25))) | (x > np.percentile(x, 75) + 1.5*(np.percentile(x, 75) - np.percentile(x, 25)))) })).reset_index() df_stats.rename(columns={'ancienneté actionnaires': 'Catégories d\'ancienneté'}, inplace=True) df_stats = df_stats.iloc[::-1].reset_index(drop=True) df_stats
    Out[ ]:
    Catégories d'ancienneté Médiane Durée actionnariat Q1 Q3 Upper Whiskers Nombre d'outliers
    0 Nouvel actionnaire en 2012 ou moins 7.75 3.900 11.2 22.1500 0.0
    1 Nouvel actionnaire entre 2012 à 2017 4.90 2.575 7.3 14.3875 0.0
    2 Nouvel actionnaire depuis 2017 ou plus 1.85 0.900 3.2 6.6500 0.0
    In [ ]:
    Copied!
    from IPython.display import display, HTML
    display(HTML("<div style='page-break-before: always;'></div>"))
    
    
    # Afficher un titre centré avec une taille de police plus grande
    display(HTML('<center><h2><u>Analyse par déciles d\'actionnaires</u></h2></center>'))
    
    from IPython.display import display, HTML display(HTML("
    ")) # Afficher un titre centré avec une taille de police plus grande display(HTML('

    Analyse par déciles d\'actionnaires

    '))

    Analyse par déciles d'actionnaires

    In [ ]:
    Copied!
    import pandas as pd
    import numpy as np
    
    # Calculer les déciles de la variable "Foncière : Nombre d'actions détenues"
    df_actionnaire = df[df["Actionnaire ?"] == True]
    df_actionnaire = df_actionnaire.drop_duplicates(subset="ID du contact")
    #df_actionnaire['Foncière : Part du capital possédée (%)'] = df_actionnaire['Foncière : Part du capital possédée (%)'].str.replace(',', '.').astype(float)
    
    # Calculer les déciles avec des intervalles égaux
    deciles = pd.qcut(df_actionnaire["Foncière : Nombre d'actions détenues"], q=10, duplicates='drop')
    # En utilisant duplicates='drop'  la fonction supprimera les bornes en double. Cela signifie que si deux valeurs identiques tombent exactement sur une limite d'intervalle, l'une des bornes sera supprimée, de sorte que chaque limite d'intervalle est unique. Cela peut entraîner un nombre réduit d'intervalles si vos données ont beaucoup de valeurs identiques.Il faut donc prévoir des intervalles en plus pour en spécifier 10  soit utiliser q = 11 au lieu de 10 
    # Utilisez ces intervalles pour découper les déciles
    df_actionnaire['déciles actionnaire'] = deciles
    df_actionnaire['déciles actionnaire'] = df_actionnaire['déciles actionnaire'].cat.codes + 1
    
    # Créer une nouvelle colonne avec la catégorie d1 à d10
    df_actionnaire['déciles actionnaires'] = 'décile ' + df_actionnaire['déciles actionnaire'].astype(str)
    
    import pandas as pd import numpy as np # Calculer les déciles de la variable "Foncière : Nombre d'actions détenues" df_actionnaire = df[df["Actionnaire ?"] == True] df_actionnaire = df_actionnaire.drop_duplicates(subset="ID du contact") #df_actionnaire['Foncière : Part du capital possédée (%)'] = df_actionnaire['Foncière : Part du capital possédée (%)'].str.replace(',', '.').astype(float) # Calculer les déciles avec des intervalles égaux deciles = pd.qcut(df_actionnaire["Foncière : Nombre d'actions détenues"], q=10, duplicates='drop') # En utilisant duplicates='drop' la fonction supprimera les bornes en double. Cela signifie que si deux valeurs identiques tombent exactement sur une limite d'intervalle, l'une des bornes sera supprimée, de sorte que chaque limite d'intervalle est unique. Cela peut entraîner un nombre réduit d'intervalles si vos données ont beaucoup de valeurs identiques.Il faut donc prévoir des intervalles en plus pour en spécifier 10 soit utiliser q = 11 au lieu de 10 # Utilisez ces intervalles pour découper les déciles df_actionnaire['déciles actionnaire'] = deciles df_actionnaire['déciles actionnaire'] = df_actionnaire['déciles actionnaire'].cat.codes + 1 # Créer une nouvelle colonne avec la catégorie d1 à d10 df_actionnaire['déciles actionnaires'] = 'décile ' + df_actionnaire['déciles actionnaire'].astype(str)
    In [ ]:
    Copied!
    df_actionnaire['multi-souscripteur ?'] = df_actionnaire['multi-souscripteur ?'].replace({True: "Multi-souscripteurs", False: "Mono-souscripteurs"})
    df_actionnaire_MS = df_actionnaire.groupby('déciles actionnaires')['multi-souscripteur ?'].value_counts().unstack().fillna(0)
    
    df_actionnaire['multi-souscripteur ?'] = df_actionnaire['multi-souscripteur ?'].replace({True: "Multi-souscripteurs", False: "Mono-souscripteurs"}) df_actionnaire_MS = df_actionnaire.groupby('déciles actionnaires')['multi-souscripteur ?'].value_counts().unstack().fillna(0)
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Bornes des déciles en fonction du nombre d'actions détenues par actionnaire</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Bornes des déciles en fonction du nombre d'actions détenues par actionnaire

    "))

    Bornes des déciles en fonction du nombre d'actions détenues par actionnaire

    In [ ]:
    Copied!
    # Calculer les déciles avec des intervalles égaux
    deciles = pd.qcut(df_actionnaire["Foncière : Nombre d'actions détenues"], q=10, duplicates='drop')
    
    # Obtenir les bornes des déciles
    decile_bounds = np.unique(deciles)
    decile_bounds
    
    # Calculer les déciles avec des intervalles égaux deciles = pd.qcut(df_actionnaire["Foncière : Nombre d'actions détenues"], q=10, duplicates='drop') # Obtenir les bornes des déciles decile_bounds = np.unique(deciles) decile_bounds
    Out[ ]:
    array([Interval(0.999, 12.0, closed='right'),
           Interval(12.0, 24.0, closed='right'),
           Interval(24.0, 37.0, closed='right'),
           Interval(37.0, 49.0, closed='right'),
           Interval(49.0, 61.0, closed='right'),
           Interval(61.0, 74.0, closed='right'),
           Interval(74.0, 85.0, closed='right'),
           Interval(85.0, 97.0, closed='right'),
           Interval(97.0, 3373.6, closed='right'),
           Interval(3373.6, 7979.0, closed='right')], dtype=object)
    In [ ]:
    Copied!
    from IPython.display import display, HTML
    
    # Première phrase
    display(HTML("<h4>Explications concernant la détermination des bornes des déciles : </h4>"))
    # Deuxième phrase
    display(HTML("<h4>Les bornes des déciles sont calculées en divisant un ensemble de données triées en dix parties égales, de sorte que chaque décile représente 10 % des observations. Il s'agit d'ordonner les données en ordre croissant (ici le nombre d'actions possédées au total), puis divisez le nombre total d'observations par 10 pour déterminer combien d'observations devraient se trouver dans chaque décile. Cependant, il peut arriver que les bornes des déciles ne séparent pas parfaitement les données en parties égales lorsque les valeurs sont fortement regroupées autour de certaines valeurs (1 action ou 2, par exemple). Dans de tels cas, plusieurs observations peuvent avoir la même valeur, ce qui peut entraîner des déciles qui ne contiennent pas exactement 10 % des données chacun.</h4>"))
    
    display(HTML("<h4>Pour le deuxième décile par exemple, celui-ci comporte toutes les personnes qui sont inclues dans l'interval 3.0, 5.0, closed='right') autrement écrit ]3-5]. Il contient alors les personnes possédant au total un nombre d'actions strictement supérieur à 3 à inférieur ou égale à 5</h4>"))
    
    from IPython.display import display, HTML # Première phrase display(HTML("

    Explications concernant la détermination des bornes des déciles :

    ")) # Deuxième phrase display(HTML("

    Les bornes des déciles sont calculées en divisant un ensemble de données triées en dix parties égales, de sorte que chaque décile représente 10 % des observations. Il s'agit d'ordonner les données en ordre croissant (ici le nombre d'actions possédées au total), puis divisez le nombre total d'observations par 10 pour déterminer combien d'observations devraient se trouver dans chaque décile. Cependant, il peut arriver que les bornes des déciles ne séparent pas parfaitement les données en parties égales lorsque les valeurs sont fortement regroupées autour de certaines valeurs (1 action ou 2, par exemple). Dans de tels cas, plusieurs observations peuvent avoir la même valeur, ce qui peut entraîner des déciles qui ne contiennent pas exactement 10 % des données chacun.

    ")) display(HTML("

    Pour le deuxième décile par exemple, celui-ci comporte toutes les personnes qui sont inclues dans l'interval 3.0, 5.0, closed='right') autrement écrit ]3-5]. Il contient alors les personnes possédant au total un nombre d'actions strictement supérieur à 3 à inférieur ou égale à 5

    "))

    Explications concernant la détermination des bornes des déciles :

    Les bornes des déciles sont calculées en divisant un ensemble de données triées en dix parties égales, de sorte que chaque décile représente 10 % des observations. Il s'agit d'ordonner les données en ordre croissant (ici le nombre d'actions possédées au total), puis divisez le nombre total d'observations par 10 pour déterminer combien d'observations devraient se trouver dans chaque décile. Cependant, il peut arriver que les bornes des déciles ne séparent pas parfaitement les données en parties égales lorsque les valeurs sont fortement regroupées autour de certaines valeurs (1 action ou 2, par exemple). Dans de tels cas, plusieurs observations peuvent avoir la même valeur, ce qui peut entraîner des déciles qui ne contiennent pas exactement 10 % des données chacun.

    Pour le deuxième décile par exemple, celui-ci comporte toutes les personnes qui sont inclues dans l'interval 3.0, 5.0, closed='right') autrement écrit ]3-5]. Il contient alors les personnes possédant au total un nombre d'actions strictement supérieur à 3 à inférieur ou égale à 5

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Répartitions des catégories de souscripteurs au sein des déciles (par multi-souscripteurs ou pas)</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Répartitions des catégories de souscripteurs au sein des déciles (par multi-souscripteurs ou pas)

    "))

    Répartitions des catégories de souscripteurs au sein des déciles (par multi-souscripteurs ou pas)

    In [ ]:
    Copied!
    import matplotlib.pyplot as plt
    
    # Supprimez cette ligne si vous n'utilisez pas Jupyter Notebook
    %matplotlib inline
    df_actionnaire_MS = df_actionnaire_MS.reindex(['décile 1', 'décile 2', 'décile 3', 'décile 4', 'décile 5', 'décile 6', 'décile 7', 'décile 8', 'décile 9', 'décile 10'])
    # Définir les données
    deciles = df_actionnaire_MS.index
    mono_souscripteurs = df_actionnaire_MS['Mono-souscripteurs']
    multi_souscripteurs = df_actionnaire_MS['Multi-souscripteurs']
    
    # Créer le graphique en barres empilées
    fig, ax = plt.subplots()
    bar1 = ax.bar(deciles, mono_souscripteurs, label='Mono-souscripteurs')
    bar2 = ax.bar(deciles, multi_souscripteurs, bottom=mono_souscripteurs, label='Multi-souscripteurs')
    
    # Pivoter les étiquettes en x de 45 degrés
    plt.xticks(rotation=45)
    
    # Ajouter des valeurs numériques au centre de chaque partie des barres
    for decile, bar_m, bar_multi in zip(deciles, bar1, bar2):
        height_m = bar_m.get_height()
        height_multi = bar_multi.get_height()
        total = height_m + height_multi
        ax.annotate(f'{height_m}', (decile, height_m/2), ha='center', va='bottom', color='black')
        ax.annotate(f'{height_multi}', (decile, height_m + height_multi/2), ha='center', va='bottom', color='black')
    
    # Ajouter des labels, un titre et une légende
    plt.xlabel('Déciles ')
    plt.ylabel('Nombre d\'actionnaires')
    plt.title('Répartition des Multi-souscripteurs par déciles')
    plt.legend()
    
    # Afficher le graphique
    plt.show()
    
    import matplotlib.pyplot as plt # Supprimez cette ligne si vous n'utilisez pas Jupyter Notebook %matplotlib inline df_actionnaire_MS = df_actionnaire_MS.reindex(['décile 1', 'décile 2', 'décile 3', 'décile 4', 'décile 5', 'décile 6', 'décile 7', 'décile 8', 'décile 9', 'décile 10']) # Définir les données deciles = df_actionnaire_MS.index mono_souscripteurs = df_actionnaire_MS['Mono-souscripteurs'] multi_souscripteurs = df_actionnaire_MS['Multi-souscripteurs'] # Créer le graphique en barres empilées fig, ax = plt.subplots() bar1 = ax.bar(deciles, mono_souscripteurs, label='Mono-souscripteurs') bar2 = ax.bar(deciles, multi_souscripteurs, bottom=mono_souscripteurs, label='Multi-souscripteurs') # Pivoter les étiquettes en x de 45 degrés plt.xticks(rotation=45) # Ajouter des valeurs numériques au centre de chaque partie des barres for decile, bar_m, bar_multi in zip(deciles, bar1, bar2): height_m = bar_m.get_height() height_multi = bar_multi.get_height() total = height_m + height_multi ax.annotate(f'{height_m}', (decile, height_m/2), ha='center', va='bottom', color='black') ax.annotate(f'{height_multi}', (decile, height_m + height_multi/2), ha='center', va='bottom', color='black') # Ajouter des labels, un titre et une légende plt.xlabel('Déciles ') plt.ylabel('Nombre d\'actionnaires') plt.title('Répartition des Multi-souscripteurs par déciles') plt.legend() # Afficher le graphique plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Nombre moyen d'actions par souscriptions entre déciles d'actionnaires</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Nombre moyen d'actions par souscriptions entre déciles d'actionnaires

    "))

    Nombre moyen d'actions par souscriptions entre déciles d'actionnaires

    In [ ]:
    Copied!
    decile_order = ['décile 1','décile 2','décile 3','décile 4','décile 5','décile 6','décile 7','décile 8','décile 9','décile 10']
    
    decile_order = ['décile 1','décile 2','décile 3','décile 4','décile 5','décile 6','décile 7','décile 8','décile 9','décile 10']
    In [ ]:
    Copied!
    df_decactionsmean = df_actionnaire.groupby("déciles actionnaires")["Foncière : Nombre d'actions détenues"].mean().to_frame()
    df_decactionsmean = df_decactionsmean.reindex(index=decile_order)
    df_decactionsmean
    
    df_decactionsmean = df_actionnaire.groupby("déciles actionnaires")["Foncière : Nombre d'actions détenues"].mean().to_frame() df_decactionsmean = df_decactionsmean.reindex(index=decile_order) df_decactionsmean
    Out[ ]:
    Foncière : Nombre d'actions détenues
    déciles actionnaires
    décile 1 6.448804
    décile 2 18.575442
    décile 3 31.300562
    décile 4 43.514781
    décile 5 55.203441
    décile 6 67.965649
    décile 7 79.898947
    décile 8 91.342209
    décile 9 1273.020790
    décile 10 5710.822355
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Nombre total d'actions entre déciles d'actionnaires</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Nombre total d'actions entre déciles d'actionnaires

    "))

    Nombre total d'actions entre déciles d'actionnaires

    In [ ]:
    Copied!
    df_decactionsum = df_actionnaire.groupby("déciles actionnaires")["Foncière : Nombre d'actions détenues"].sum().to_frame()
    df_decactionsum = df_decactionsum.reindex(['décile 1', 'décile 2', 'décile 3', 'décile 4', 'décile 5', 'décile 6', 'décile 7', 'décile 8', 'décile 9', 'décile 10'])
    df_decactionsum
    
    df_decactionsum = df_actionnaire.groupby("déciles actionnaires")["Foncière : Nombre d'actions détenues"].sum().to_frame() df_decactionsum = df_decactionsum.reindex(['décile 1', 'décile 2', 'décile 3', 'décile 4', 'décile 5', 'décile 6', 'décile 7', 'décile 8', 'décile 9', 'décile 10']) df_decactionsum
    Out[ ]:
    Foncière : Nombre d'actions détenues
    déciles actionnaires
    décile 1 6739
    décile 2 17851
    décile 3 33429
    décile 4 42688
    décile 5 54541
    décile 6 71228
    décile 7 75904
    décile 8 92621
    décile 9 1224646
    décile 10 5722244
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Nombre moyen de souscriptions entre déciles d'actionnaires</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Nombre moyen de souscriptions entre déciles d'actionnaires

    "))

    Nombre moyen de souscriptions entre déciles d'actionnaires

    In [ ]:
    Copied!
    df_decsouscriptionmean = df_actionnaire.groupby("déciles actionnaires")["Nombre de souscriptions"].mean().to_frame()
    df_decsouscriptionmean = df_decsouscriptionmean.reindex(['décile 1', 'décile 2', 'décile 3', 'décile 4', 'décile 5', 'décile 6', 'décile 7', 'décile 8', 'décile 9', 'décile 10'])
    df_decsouscriptionmean
    
    df_decsouscriptionmean = df_actionnaire.groupby("déciles actionnaires")["Nombre de souscriptions"].mean().to_frame() df_decsouscriptionmean = df_decsouscriptionmean.reindex(['décile 1', 'décile 2', 'décile 3', 'décile 4', 'décile 5', 'décile 6', 'décile 7', 'décile 8', 'décile 9', 'décile 10']) df_decsouscriptionmean
    Out[ ]:
    Nombre de souscriptions
    déciles actionnaires
    décile 1 1.656182
    décile 2 1.656361
    décile 3 1.624599
    décile 4 1.658933
    décile 5 1.668192
    décile 6 1.560638
    décile 7 1.603345
    décile 8 1.597520
    décile 9 1.627521
    décile 10 1.646048
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Nombre total de souscriptions entre déciles d'actionnaires</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Nombre total de souscriptions entre déciles d'actionnaires

    "))

    Nombre total de souscriptions entre déciles d'actionnaires

    In [ ]:
    Copied!
    df_decsouscriptionsum = df_actionnaire.groupby("déciles actionnaires")["Nombre de souscriptions"].sum().to_frame()
    df_decsouscriptionsum = df_decsouscriptionsum.reindex(['décile 1', 'décile 2', 'décile 3', 'décile 4', 'décile 5', 'décile 6', 'décile 7', 'décile 8', 'décile 9', 'décile 10'])
    df_decsouscriptionsum
    
    df_decsouscriptionsum = df_actionnaire.groupby("déciles actionnaires")["Nombre de souscriptions"].sum().to_frame() df_decsouscriptionsum = df_decsouscriptionsum.reindex(['décile 1', 'décile 2', 'décile 3', 'décile 4', 'décile 5', 'décile 6', 'décile 7', 'décile 8', 'décile 9', 'décile 10']) df_decsouscriptionsum
    Out[ ]:
    Nombre de souscriptions
    déciles actionnaires
    décile 1 1527.0
    décile 2 1393.0
    décile 3 1519.0
    décile 4 1430.0
    décile 5 1458.0
    décile 6 1467.0
    décile 7 1342.0
    décile 8 1417.0
    décile 9 1372.0
    décile 10 1437.0
    In [ ]:
    Copied!
    import matplotlib.pyplot as plt
    import numpy as np
    
    
    # Remplacer les virgules par des points dans la colonne 'Foncière : Capital possédé'
    #df_actionnaire['Foncière : Capital possédé'] = df_actionnaire['Foncière : Capital possédé'].str.replace(',', '.')
    #df_actionnaire['Foncière : Part du capital possédée (%)'] = df_actionnaire['Foncière : Part du capital possédée (%)'].str.replace(',', '.')
    
    # Convertir la colonne 'Foncière : Capital possédé' en valeurs numériques
    df_actionnaire['Foncière : Capital possédé'] = pd.to_numeric(df_actionnaire['Foncière : Capital possédé'], errors='coerce')
    df_actionnaire['Foncière : Part du capital possédée (%)'] = pd.to_numeric(df_actionnaire['Foncière : Part du capital possédée (%)'], errors='coerce')
    
    # Calcul de la part de chaque décile d'actionnaires dans le total
    df_grouped = df_actionnaire.groupby('déciles actionnaires').agg({
        'Foncière : Capital possédé': 'sum',
        'Foncière : Part du capital possédée (%)': 'sum'
    })
    total_capital = df_grouped['Foncière : Capital possédé'].sum() #Avec cette ligne et la ligne de dessous on voit qu'on calcul le total avec le capital possédé et non la part du capital possédé qui inclut les PM
    
    df_grouped['Part du capital possédé (%)'] = df_grouped['Foncière : Capital possédé'] / total_capital * 100
    
    # Affichage du tableau
    df_grouped = df_grouped[['Foncière : Part du capital possédée (%)']]
    df_grouped.index.name = 'Déciles actionnaire'
    
    # Position des barres
    x = np.arange(len(df_grouped))
    width = 0.35
    
    df_grouped = df_grouped.reindex(index=decile_order)
    
    # Création du graphique à barres
    fig, ax = plt.subplots()
    
    # Barres pour la part du capital possédé
    bar1 = ax.bar(x, df_grouped['Foncière : Part du capital possédée (%)'], width, label='Part du capital possédé')
    
    # Étiquettes des axes et du titre
    ax.set_xlabel('Déciles actionnaire')
    ax.set_ylabel('Pourcentage (%)')
    ax.set_title("Répartition du capital par déciles d'actionnaires")
    
    # Positions des étiquettes sur l'axe x
    ax.set_xticks(x)
    ax.set_xticklabels(df_grouped.index, rotation=45, ha='right')  # Inclinaison de 45 degrés avec alignement à droite
    
    # Légende
    ax.legend()
    
    # Affichage des valeurs au-dessus des barres
    for rect in bar1:
        height = rect.get_height()
        ax.text(rect.get_x() + rect.get_width() / 2, height + 1, f'{height:.1f}%', ha='center')
    
    # Affichage du graphique
    plt.tight_layout()  # Ajustement automatique des marges
    plt.show()
    
    import matplotlib.pyplot as plt import numpy as np # Remplacer les virgules par des points dans la colonne 'Foncière : Capital possédé' #df_actionnaire['Foncière : Capital possédé'] = df_actionnaire['Foncière : Capital possédé'].str.replace(',', '.') #df_actionnaire['Foncière : Part du capital possédée (%)'] = df_actionnaire['Foncière : Part du capital possédée (%)'].str.replace(',', '.') # Convertir la colonne 'Foncière : Capital possédé' en valeurs numériques df_actionnaire['Foncière : Capital possédé'] = pd.to_numeric(df_actionnaire['Foncière : Capital possédé'], errors='coerce') df_actionnaire['Foncière : Part du capital possédée (%)'] = pd.to_numeric(df_actionnaire['Foncière : Part du capital possédée (%)'], errors='coerce') # Calcul de la part de chaque décile d'actionnaires dans le total df_grouped = df_actionnaire.groupby('déciles actionnaires').agg({ 'Foncière : Capital possédé': 'sum', 'Foncière : Part du capital possédée (%)': 'sum' }) total_capital = df_grouped['Foncière : Capital possédé'].sum() #Avec cette ligne et la ligne de dessous on voit qu'on calcul le total avec le capital possédé et non la part du capital possédé qui inclut les PM df_grouped['Part du capital possédé (%)'] = df_grouped['Foncière : Capital possédé'] / total_capital * 100 # Affichage du tableau df_grouped = df_grouped[['Foncière : Part du capital possédée (%)']] df_grouped.index.name = 'Déciles actionnaire' # Position des barres x = np.arange(len(df_grouped)) width = 0.35 df_grouped = df_grouped.reindex(index=decile_order) # Création du graphique à barres fig, ax = plt.subplots() # Barres pour la part du capital possédé bar1 = ax.bar(x, df_grouped['Foncière : Part du capital possédée (%)'], width, label='Part du capital possédé') # Étiquettes des axes et du titre ax.set_xlabel('Déciles actionnaire') ax.set_ylabel('Pourcentage (%)') ax.set_title("Répartition du capital par déciles d'actionnaires") # Positions des étiquettes sur l'axe x ax.set_xticks(x) ax.set_xticklabels(df_grouped.index, rotation=45, ha='right') # Inclinaison de 45 degrés avec alignement à droite # Légende ax.legend() # Affichage des valeurs au-dessus des barres for rect in bar1: height = rect.get_height() ax.text(rect.get_x() + rect.get_width() / 2, height + 1, f'{height:.1f}%', ha='center') # Affichage du graphique plt.tight_layout() # Ajustement automatique des marges plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>La structure des données fait qu'il n'y pas le même nombre de personnes dans chaque déciles ce qui peut déséquilibré les parts (ex : le 2ème décile possède moins que le premier)</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    La structure des données fait qu'il n'y pas le même nombre de personnes dans chaque déciles ce qui peut déséquilibré les parts (ex : le 2ème décile possède moins que le premier)

    "))

    La structure des données fait qu'il n'y pas le même nombre de personnes dans chaque déciles ce qui peut déséquilibré les parts (ex : le 2ème décile possède moins que le premier)

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Ici lorsqu\'on parle de part du capital possédé, il s\'agit de la part possédé sur l\'ensemble du capital des personnes physiques et morales</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Ici lorsqu\'on parle de part du capital possédé, il s\'agit de la part possédé sur l\'ensemble du capital des personnes physiques et morales

    "))

    Ici lorsqu'on parle de part du capital possédé, il s'agit de la part possédé sur l'ensemble du capital des personnes physiques et morales

    In [ ]:
    Copied!
    from IPython.display import display, HTML
    
    display(HTML("<div style='page-break-before: always;'></div>"))
    
    # Afficher un titre centré avec une taille de police plus grande
    display(HTML('<center><h2><u>Focus sur le 9ème décile</u></h2></center>'))
    
    from IPython.display import display, HTML display(HTML("
    ")) # Afficher un titre centré avec une taille de police plus grande display(HTML('

    Focus sur le 9ème décile

    '))

    Focus sur le 9ème décile

    In [ ]:
    Copied!
    df_actionnaire10 = df_actionnaire[df_actionnaire["déciles actionnaires"] == "décile 10"]
    
    df_actionnaire10 = df_actionnaire[df_actionnaire["déciles actionnaires"] == "décile 10"]
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Nous avons divisé le 10 ème décile de tous les actionnaires en 10 déciles supplémentaires. il s'agit donc de s'intéresser aux 10 derniers centiles</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Nous avons divisé le 10 ème décile de tous les actionnaires en 10 déciles supplémentaires. il s'agit donc de s'intéresser aux 10 derniers centiles

    "))

    Nous avons divisé le 10 ème décile de tous les actionnaires en 10 déciles supplémentaires. il s'agit donc de s'intéresser aux 10 derniers centiles

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Détermination des bornes des déciles parmi le 10eme décile de tous les actionnaires, nombre de personnes par décile et nombre d'actions détenues en fonction des déciles </h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Détermination des bornes des déciles parmi le 10eme décile de tous les actionnaires, nombre de personnes par décile et nombre d'actions détenues en fonction des déciles

    "))

    Détermination des bornes des déciles parmi le 10eme décile de tous les actionnaires, nombre de personnes par décile et nombre d'actions détenues en fonction des déciles

    In [ ]:
    Copied!
    # Calculer les déciles avec des intervalles égaux
    deciles = pd.qcut(df_actionnaire10["Foncière : Nombre d'actions détenues"], q=10, duplicates='drop')
    # Obtenir les bornes des déciles
    decile_bounds = np.unique(deciles)
    decile_bounds
    
    # Calculer les déciles avec des intervalles égaux deciles = pd.qcut(df_actionnaire10["Foncière : Nombre d'actions détenues"], q=10, duplicates='drop') # Obtenir les bornes des déciles decile_bounds = np.unique(deciles) decile_bounds
    Out[ ]:
    array([Interval(3383.999, 3842.8, closed='right'),
           Interval(3842.8, 4303.2, closed='right'),
           Interval(4303.2, 4816.9, closed='right'),
           Interval(4816.9, 5301.6, closed='right'),
           Interval(5301.6, 5715.5, closed='right'),
           Interval(5715.5, 6159.6, closed='right'),
           Interval(6159.6, 6678.5, closed='right'),
           Interval(6678.5, 7084.0, closed='right'),
           Interval(7084.0, 7529.7, closed='right'),
           Interval(7529.7, 7979.0, closed='right')], dtype=object)
    In [ ]:
    Copied!
    df_actionnaire10 = df_actionnaire10.sort_values(by="Foncière : Nombre d'actions détenues")
    
    # Calculer les déciles avec des intervalles égaux
    deciles = pd.qcut(df_actionnaire10["Foncière : Nombre d'actions détenues"], q=10, duplicates='drop')
    
    # Utilisez ces intervalles pour découper les déciles
    df_actionnaire10['catégories centiles actionnaires'] = deciles
    df_actionnaire10['catégories centiles actionnaires'] = df_actionnaire10['catégories centiles actionnaires'].cat.codes + 1
    
    # Créer une nouvelle colonne avec la catégorie d1 à d9
    df_actionnaire10['catégories centiles actionnaires'] = 'C' + df_actionnaire10['catégories centiles actionnaires'].astype(str)
    
    df_actionnaire10 = df_actionnaire10.sort_values(by="Foncière : Nombre d'actions détenues") # Calculer les déciles avec des intervalles égaux deciles = pd.qcut(df_actionnaire10["Foncière : Nombre d'actions détenues"], q=10, duplicates='drop') # Utilisez ces intervalles pour découper les déciles df_actionnaire10['catégories centiles actionnaires'] = deciles df_actionnaire10['catégories centiles actionnaires'] = df_actionnaire10['catégories centiles actionnaires'].cat.codes + 1 # Créer une nouvelle colonne avec la catégorie d1 à d9 df_actionnaire10['catégories centiles actionnaires'] = 'C' + df_actionnaire10['catégories centiles actionnaires'].astype(str)
    In [ ]:
    Copied!
     nouveaux_noms = {
        'C1': 'C90',
        'C2': 'C91',
        'C3': 'C92',
        'C4': 'C93',
        'C5': 'C94',
        'C6': 'C95',
        'C7': 'C96',
        'C8': 'C97',
        'C9': 'C98',
        'C10': 'C99'
    }
    
    df_actionnaire10['catégories centiles actionnaires'] = df_actionnaire10['catégories centiles actionnaires'].replace(nouveaux_noms)
    
    nouveaux_noms = { 'C1': 'C90', 'C2': 'C91', 'C3': 'C92', 'C4': 'C93', 'C5': 'C94', 'C6': 'C95', 'C7': 'C96', 'C8': 'C97', 'C9': 'C98', 'C10': 'C99' } df_actionnaire10['catégories centiles actionnaires'] = df_actionnaire10['catégories centiles actionnaires'].replace(nouveaux_noms)
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Répartition des catégories de souscripteurs au sein des 10 derniers centiles (par multi-souscripteurs ou pas)</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Répartition des catégories de souscripteurs au sein des 10 derniers centiles (par multi-souscripteurs ou pas)

    "))

    Répartition des catégories de souscripteurs au sein des 10 derniers centiles (par multi-souscripteurs ou pas)

    In [ ]:
    Copied!
    df_actionnaire10['multi-souscripteur ?'] = df_actionnaire10['multi-souscripteur ?'].replace({True: "Multi-souscripteurs", False: "Mono-souscripteurs"})
    df_actionnaire_MS10 = df_actionnaire10.groupby('catégories centiles actionnaires')['multi-souscripteur ?'].value_counts().unstack().fillna(0)
    df_actionnaire_MS10 = df_actionnaire_MS10.reindex(['C90', 'C91', 'C92', 'C93', 'C94', 'C95', 'C96', 'C97', 'C98', 'C99'])
    df_actionnaire_MS10
    
    df_actionnaire10['multi-souscripteur ?'] = df_actionnaire10['multi-souscripteur ?'].replace({True: "Multi-souscripteurs", False: "Mono-souscripteurs"}) df_actionnaire_MS10 = df_actionnaire10.groupby('catégories centiles actionnaires')['multi-souscripteur ?'].value_counts().unstack().fillna(0) df_actionnaire_MS10 = df_actionnaire_MS10.reindex(['C90', 'C91', 'C92', 'C93', 'C94', 'C95', 'C96', 'C97', 'C98', 'C99']) df_actionnaire_MS10
    Out[ ]:
    multi-souscripteur ? Mono-souscripteurs Multi-souscripteurs
    catégories centiles actionnaires
    C90 53 48
    C91 46 54
    C92 55 45
    C93 48 52
    C94 55 45
    C95 61 39
    C96 54 46
    C97 52 49
    C98 52 47
    C99 56 45
    In [ ]:
    Copied!
    import matplotlib.pyplot as plt
    
    # Supprimez cette ligne si vous n'utilisez pas Jupyter Notebook
    %matplotlib inline
    
    # Définir les données
    deciles = df_actionnaire_MS10.index
    mono_souscripteurs = df_actionnaire_MS10['Mono-souscripteurs']
    multi_souscripteurs = df_actionnaire_MS10['Multi-souscripteurs']
    
    # Créer le graphique en barres empilées
    fig, ax = plt.subplots()
    bar1 = ax.bar(deciles, mono_souscripteurs, label='Mono-souscripteurs')
    bar2 = ax.bar(deciles, multi_souscripteurs, bottom=mono_souscripteurs, label='Multi-souscripteurs')
    
    # Pivoter les étiquettes en x de 45 degrés
    plt.xticks(rotation=45)
    
    # Ajouter des valeurs numériques au centre de chaque partie des barres
    for decile, bar_m, bar_multi in zip(deciles, bar1, bar2):
        height_m = bar_m.get_height()
        height_multi = bar_multi.get_height()
        total = height_m + height_multi
        ax.annotate(f'{height_m}', (decile, height_m/2), ha='center', va='bottom', color='black')
        ax.annotate(f'{height_multi}', (decile, height_m + height_multi/2), ha='center', va='bottom', color='black')
    
    # Ajouter des labels, un titre et une légende
    plt.xlabel('Catégories Centiles Actionnaires')
    plt.ylabel('Nombre')
    plt.title('Répartition des multi-souscripteurs par catégories centiles actionnaires')
    plt.legend()
    
    # Afficher le graphique
    plt.show()
    
    import matplotlib.pyplot as plt # Supprimez cette ligne si vous n'utilisez pas Jupyter Notebook %matplotlib inline # Définir les données deciles = df_actionnaire_MS10.index mono_souscripteurs = df_actionnaire_MS10['Mono-souscripteurs'] multi_souscripteurs = df_actionnaire_MS10['Multi-souscripteurs'] # Créer le graphique en barres empilées fig, ax = plt.subplots() bar1 = ax.bar(deciles, mono_souscripteurs, label='Mono-souscripteurs') bar2 = ax.bar(deciles, multi_souscripteurs, bottom=mono_souscripteurs, label='Multi-souscripteurs') # Pivoter les étiquettes en x de 45 degrés plt.xticks(rotation=45) # Ajouter des valeurs numériques au centre de chaque partie des barres for decile, bar_m, bar_multi in zip(deciles, bar1, bar2): height_m = bar_m.get_height() height_multi = bar_multi.get_height() total = height_m + height_multi ax.annotate(f'{height_m}', (decile, height_m/2), ha='center', va='bottom', color='black') ax.annotate(f'{height_multi}', (decile, height_m + height_multi/2), ha='center', va='bottom', color='black') # Ajouter des labels, un titre et une légende plt.xlabel('Catégories Centiles Actionnaires') plt.ylabel('Nombre') plt.title('Répartition des multi-souscripteurs par catégories centiles actionnaires') plt.legend() # Afficher le graphique plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    df_actiondécile = df_actionnaire10.groupby('catégories centiles actionnaires')["Foncière : Capital possédé"].sum().to_frame()
    df_actiondécile = df_actiondécile.reindex(['C90', 'C91', 'C92', 'C93', 'C94', 'C95', 'C96', 'C97', 'C98', 'C99'])
    df_actiondécile
    
    df_actiondécile = df_actionnaire10.groupby('catégories centiles actionnaires')["Foncière : Capital possédé"].sum().to_frame() df_actiondécile = df_actiondécile.reindex(['C90', 'C91', 'C92', 'C93', 'C94', 'C95', 'C96', 'C97', 'C98', 'C99']) df_actiondécile
    Out[ ]:
    Foncière : Capital possédé
    catégories centiles actionnaires
    C90 38319960
    C91 42962010
    C92 47706855
    C93 53470935
    C94 57795780
    C95 62259750
    C96 67156215
    C97 73106460
    C98 75981990
    C99 82075665
    In [ ]:
    Copied!
    df_actiondécile = df_actionnaire10.groupby('catégories centiles actionnaires')["Foncière : Nombre d'actions détenues"].sum().to_frame()
    df_actiondécile = df_actiondécile.reindex(['C90', 'C91', 'C92', 'C93', 'C94', 'C95', 'C96', 'C97', 'C98', 'C99'])
    df_actiondécile
    
    df_actiondécile = df_actionnaire10.groupby('catégories centiles actionnaires')["Foncière : Nombre d'actions détenues"].sum().to_frame() df_actiondécile = df_actiondécile.reindex(['C90', 'C91', 'C92', 'C93', 'C94', 'C95', 'C96', 'C97', 'C98', 'C99']) df_actiondécile
    Out[ ]:
    Foncière : Nombre d'actions détenues
    catégories centiles actionnaires
    C90 364952
    C91 409162
    C92 454351
    C93 509247
    C94 550436
    C95 592950
    C96 639583
    C97 696252
    C98 723638
    C99 781673
    In [ ]:
    Copied!
    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt
    
    # Supposons que vous avez déjà créé la DataFrame df_actiondécile
    
    # Créer le diagramme à barres
    plt.figure(figsize=(10, 6))
    bars = plt.bar(df_actiondécile.index, df_actiondécile["Foncière : Nombre d'actions détenues"])
    
    # Ajouter des étiquettes de valeurs sur les barres
    for bar in bars:
        height = bar.get_height()
        plt.annotate(f"{height:.0f}", xy=(bar.get_x() + bar.get_width() / 2, height),
                     xytext=(0, 3), textcoords="offset points", ha='center', va='bottom')
    
    # Ajouter des titres et des labels
    plt.title("Somme des actions détenues par catégories de centiles actionnaires")
    plt.xlabel("Catégories centiles actionnaires")
    plt.ylabel("Somme des actions détenues")
    
    # Afficher le diagramme
    plt.show()
    
    import pandas as pd import numpy as np import matplotlib.pyplot as plt # Supposons que vous avez déjà créé la DataFrame df_actiondécile # Créer le diagramme à barres plt.figure(figsize=(10, 6)) bars = plt.bar(df_actiondécile.index, df_actiondécile["Foncière : Nombre d'actions détenues"]) # Ajouter des étiquettes de valeurs sur les barres for bar in bars: height = bar.get_height() plt.annotate(f"{height:.0f}", xy=(bar.get_x() + bar.get_width() / 2, height), xytext=(0, 3), textcoords="offset points", ha='center', va='bottom') # Ajouter des titres et des labels plt.title("Somme des actions détenues par catégories de centiles actionnaires") plt.xlabel("Catégories centiles actionnaires") plt.ylabel("Somme des actions détenues") # Afficher le diagramme plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    # Calcul de la part de chaque décile d'actionnaires dans le total
    df_grouped = df_actionnaire10.groupby('catégories centiles actionnaires').agg({
        'Foncière : Part du capital possédée (%)': 'sum'
    })
    df_grouped = df_grouped.reindex(['C90', 'C91', 'C92', 'C93', 'C94', 'C95', 'C96', 'C97', 'C98', 'C99'])
    # Affichage du tableau
    df_grouped = df_grouped[['Foncière : Part du capital possédée (%)']]
    df_grouped.index.name = 'Déciles actionnaire'
    
    # Position des barres
    x = np.arange(len(df_grouped))
    width = 0.35
    
    # Création du graphique à barres
    fig, ax = plt.subplots()
    
    # Barres pour la part du capital possédé
    bar1 = ax.bar(x, df_grouped['Foncière : Part du capital possédée (%)'], width, label='Part du capital possédé')
    
    # Étiquettes des axes et du titre
    ax.set_xlabel('Déciles actionnaire')
    ax.set_ylabel('Pourcentage (%)')
    ax.set_title("Répartition du capital parmi les 9 derniers centiles d'actionnaires", pad=20)  # Augmenter la distance du titre au cadre
    
    # Positions des étiquettes sur l'axe x
    ax.set_xticks(x)
    ax.set_xticklabels(df_grouped.index, rotation=45, ha='right')  # Inclinaison de 45 degrés avec alignement à droite
    
    # Légende
    ax.legend()
    
    # Affichage des valeurs au-dessus des barres
    for rect in bar1:
        height = rect.get_height()
        ax.text(rect.get_x() + rect.get_width() / 2, height + 1, f'{height:.1f}%', ha='center')
    
    # Affichage du graphique
    plt.tight_layout()  # Ajustement automatique des marges
    plt.show()
    
    # Calcul de la part de chaque décile d'actionnaires dans le total df_grouped = df_actionnaire10.groupby('catégories centiles actionnaires').agg({ 'Foncière : Part du capital possédée (%)': 'sum' }) df_grouped = df_grouped.reindex(['C90', 'C91', 'C92', 'C93', 'C94', 'C95', 'C96', 'C97', 'C98', 'C99']) # Affichage du tableau df_grouped = df_grouped[['Foncière : Part du capital possédée (%)']] df_grouped.index.name = 'Déciles actionnaire' # Position des barres x = np.arange(len(df_grouped)) width = 0.35 # Création du graphique à barres fig, ax = plt.subplots() # Barres pour la part du capital possédé bar1 = ax.bar(x, df_grouped['Foncière : Part du capital possédée (%)'], width, label='Part du capital possédé') # Étiquettes des axes et du titre ax.set_xlabel('Déciles actionnaire') ax.set_ylabel('Pourcentage (%)') ax.set_title("Répartition du capital parmi les 9 derniers centiles d'actionnaires", pad=20) # Augmenter la distance du titre au cadre # Positions des étiquettes sur l'axe x ax.set_xticks(x) ax.set_xticklabels(df_grouped.index, rotation=45, ha='right') # Inclinaison de 45 degrés avec alignement à droite # Légende ax.legend() # Affichage des valeurs au-dessus des barres for rect in bar1: height = rect.get_height() ax.text(rect.get_x() + rect.get_width() / 2, height + 1, f'{height:.1f}%', ha='center') # Affichage du graphique plt.tight_layout() # Ajustement automatique des marges plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Clé de lecture : 1 % des actionnaires (C99) possèdent 238 848 actions soit presque 16,4 % du capital total</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Clé de lecture : 1 % des actionnaires (C99) possèdent 238 848 actions soit presque 16,4 % du capital total

    "))

    Clé de lecture : 1 % des actionnaires (C99) possèdent 238 848 actions soit presque 16,4 % du capital total

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Répartition des âges parmi les 10 derniers centiles </h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Répartition des âges parmi les 10 derniers centiles

    "))

    Répartition des âges parmi les 10 derniers centiles

    In [ ]:
    Copied!
    df_Dage = pd.crosstab(index=df_actionnaire10['catégories âge'], columns=df_actionnaire10['catégories centiles actionnaires'], margins=True, margins_name='Total')
    df_Dage
    
    df_Dage = pd.crosstab(index=df_actionnaire10['catégories âge'], columns=df_actionnaire10['catégories centiles actionnaires'], margins=True, margins_name='Total') df_Dage
    Out[ ]:
    catégories centiles actionnaires C90 C91 C92 C93 C94 C95 C96 C97 C98 C99 Total
    catégories âge
    0-25 ans 32 28 26 27 26 32 23 38 31 28 291
    25-40 ans 14 12 19 12 15 15 19 12 13 14 145
    40-60 ans 23 30 20 28 24 20 19 19 24 20 227
    60 ans et plus 32 30 35 33 35 33 39 32 31 39 339
    Total 101 100 100 100 100 100 100 101 99 101 1002
    In [ ]:
    Copied!
    df_col_percent = df_Dage.copy()
    df_col_percent = df_col_percent.div(df_col_percent.loc['Total']) * 100
    df_col_percent = df_col_percent.round(1)
    df_col_percent.iloc[-1] = df_col_percent.iloc[:-1].sum() 
    df_col_percent
    
    df_col_percent = df_Dage.copy() df_col_percent = df_col_percent.div(df_col_percent.loc['Total']) * 100 df_col_percent = df_col_percent.round(1) df_col_percent.iloc[-1] = df_col_percent.iloc[:-1].sum() df_col_percent
    Out[ ]:
    catégories centiles actionnaires C90 C91 C92 C93 C94 C95 C96 C97 C98 C99 Total
    catégories âge
    0-25 ans 31.7 28.0 26.0 27.0 26.0 32.0 23.0 37.6 31.3 27.7 29.0
    25-40 ans 13.9 12.0 19.0 12.0 15.0 15.0 19.0 11.9 13.1 13.9 14.5
    40-60 ans 22.8 30.0 20.0 28.0 24.0 20.0 19.0 18.8 24.2 19.8 22.7
    60 ans et plus 31.7 30.0 35.0 33.0 35.0 33.0 39.0 31.7 31.3 38.6 33.8
    Total 100.1 100.0 100.0 100.0 100.0 100.0 100.0 100.0 99.9 100.0 100.0
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Presque 2/3 des actionnaires du dernier centile ont plus de 60 ans</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Presque 2/3 des actionnaires du dernier centile ont plus de 60 ans

    "))

    Presque 2/3 des actionnaires du dernier centile ont plus de 60 ans

    In [ ]:
    Copied!
    df_row_percent = df_Dage.copy()
    df_row_percent.iloc[:, :-1] = df_row_percent.iloc[:, :-1].div(df_row_percent['Total'], axis=0) * 100
    df_row_percent = df_row_percent.round(1)
    df_row_percent['Total'] = df_row_percent.iloc[:, :-1].sum(axis=1) 
    df_row_percent
    
    df_row_percent = df_Dage.copy() df_row_percent.iloc[:, :-1] = df_row_percent.iloc[:, :-1].div(df_row_percent['Total'], axis=0) * 100 df_row_percent = df_row_percent.round(1) df_row_percent['Total'] = df_row_percent.iloc[:, :-1].sum(axis=1) df_row_percent
    Out[ ]:
    catégories centiles actionnaires C90 C91 C92 C93 C94 C95 C96 C97 C98 C99 Total
    catégories âge
    0-25 ans 11.0 9.6 8.9 9.3 8.9 11.0 7.9 13.1 10.7 9.6 100.0
    25-40 ans 9.7 8.3 13.1 8.3 10.3 10.3 13.1 8.3 9.0 9.7 100.1
    40-60 ans 10.1 13.2 8.8 12.3 10.6 8.8 8.4 8.4 10.6 8.8 100.0
    60 ans et plus 9.4 8.8 10.3 9.7 10.3 9.7 11.5 9.4 9.1 11.5 99.7
    Total 10.1 10.0 10.0 10.0 10.0 10.0 10.0 10.1 9.9 10.1 100.2
    In [ ]:
    Copied!
    df_DMS = pd.crosstab(index=df_actionnaire10['Catégories souscripteurs'], columns=df_actionnaire10['catégories centiles actionnaires'], margins=True, margins_name='Total')
    df_DMC = pd.crosstab(index=df_actionnaire10['multi-casquette ?'], columns=df_actionnaire10['catégories centiles actionnaires'], margins=True, margins_name='Total')
    df_Dancienneté = pd.crosstab(index=df_actionnaire10['ancienneté actionnaires'], columns=df_actionnaire10['catégories centiles actionnaires'], margins=True, margins_name='Total')
    
    df_DMS = pd.crosstab(index=df_actionnaire10['Catégories souscripteurs'], columns=df_actionnaire10['catégories centiles actionnaires'], margins=True, margins_name='Total') df_DMC = pd.crosstab(index=df_actionnaire10['multi-casquette ?'], columns=df_actionnaire10['catégories centiles actionnaires'], margins=True, margins_name='Total') df_Dancienneté = pd.crosstab(index=df_actionnaire10['ancienneté actionnaires'], columns=df_actionnaire10['catégories centiles actionnaires'], margins=True, margins_name='Total')
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Répartition des nombres de souscriptions au sein du 10eme décile </h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Répartition des nombres de souscriptions au sein du 10eme décile

    "))

    Répartition des nombres de souscriptions au sein du 10eme décile

    In [ ]:
    Copied!
    ordre_categories = ['1 souscription', '2 souscriptions', '3 à 5 souscriptions', '6 à 10 souscriptions', '10 souscriptions et plus', "Total"]
    df_DMS = df_DMS.reindex(ordre_categories)
    df_DMS
    
    ordre_categories = ['1 souscription', '2 souscriptions', '3 à 5 souscriptions', '6 à 10 souscriptions', '10 souscriptions et plus', "Total"] df_DMS = df_DMS.reindex(ordre_categories) df_DMS
    Out[ ]:
    catégories centiles actionnaires C90 C91 C92 C93 C94 C95 C96 C97 C98 C99 Total
    Catégories souscripteurs
    1 souscription 50 50 52 44 58 57 48 52 53 54 518
    2 souscriptions 26 24 25 31 19 20 25 26 23 18 237
    3 à 5 souscriptions 11 12 12 9 12 8 12 10 10 13 109
    6 à 10 souscriptions 1 0 0 1 1 1 0 0 1 1 6
    10 souscriptions et plus 13 14 11 15 10 14 15 13 12 15 132
    Total 101 100 100 100 100 100 100 101 99 101 1002
    In [ ]:
    Copied!
    df_col_percent = df_DMS.copy()
    df_col_percent = df_col_percent.div(df_col_percent.loc['Total']) * 100
    df_col_percent = df_col_percent.round(1)
    df_col_percent.iloc[-1] = df_col_percent.iloc[:-1].sum() 
    df_col_percent
    
    df_col_percent = df_DMS.copy() df_col_percent = df_col_percent.div(df_col_percent.loc['Total']) * 100 df_col_percent = df_col_percent.round(1) df_col_percent.iloc[-1] = df_col_percent.iloc[:-1].sum() df_col_percent
    Out[ ]:
    catégories centiles actionnaires C90 C91 C92 C93 C94 C95 C96 C97 C98 C99 Total
    Catégories souscripteurs
    1 souscription 49.5 50.0 52.0 44.0 58.0 57.0 48.0 51.5 53.5 53.5 51.7
    2 souscriptions 25.7 24.0 25.0 31.0 19.0 20.0 25.0 25.7 23.2 17.8 23.7
    3 à 5 souscriptions 10.9 12.0 12.0 9.0 12.0 8.0 12.0 9.9 10.1 12.9 10.9
    6 à 10 souscriptions 1.0 0.0 0.0 1.0 1.0 1.0 0.0 0.0 1.0 1.0 0.6
    10 souscriptions et plus 12.9 14.0 11.0 15.0 10.0 14.0 15.0 12.9 12.1 14.9 13.2
    Total 100.0 100.0 100.0 100.0 100.0 100.0 100.0 100.0 99.9 100.1 100.1
    In [ ]:
    Copied!
    df_row_percent = df_DMS.copy()
    df_row_percent.iloc[:, :-1] = df_row_percent.iloc[:, :-1].div(df_row_percent['Total'], axis=0) * 100
    df_row_percent = df_row_percent.round(1)
    df_row_percent['Total'] = df_row_percent.iloc[:, :-1].sum(axis=1) 
    df_row_percent
    
    df_row_percent = df_DMS.copy() df_row_percent.iloc[:, :-1] = df_row_percent.iloc[:, :-1].div(df_row_percent['Total'], axis=0) * 100 df_row_percent = df_row_percent.round(1) df_row_percent['Total'] = df_row_percent.iloc[:, :-1].sum(axis=1) df_row_percent
    Out[ ]:
    catégories centiles actionnaires C90 C91 C92 C93 C94 C95 C96 C97 C98 C99 Total
    Catégories souscripteurs
    1 souscription 9.7 9.7 10.0 8.5 11.2 11.0 9.3 10.0 10.2 10.4 100.0
    2 souscriptions 11.0 10.1 10.5 13.1 8.0 8.4 10.5 11.0 9.7 7.6 99.9
    3 à 5 souscriptions 10.1 11.0 11.0 8.3 11.0 7.3 11.0 9.2 9.2 11.9 100.0
    6 à 10 souscriptions 16.7 0.0 0.0 16.7 16.7 16.7 0.0 0.0 16.7 16.7 100.2
    10 souscriptions et plus 9.8 10.6 8.3 11.4 7.6 10.6 11.4 9.8 9.1 11.4 100.0
    Total 10.1 10.0 10.0 10.0 10.0 10.0 10.0 10.1 9.9 10.1 100.2
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Répartition des types de multi-engagement parmi les 10 derniers centiles </h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Répartition des types de multi-engagement parmi les 10 derniers centiles

    "))

    Répartition des types de multi-engagement parmi les 10 derniers centiles

    In [ ]:
    Copied!
    df_DMC
    
    df_DMC
    Out[ ]:
    catégories centiles actionnaires C90 C91 C92 C93 C94 C95 C96 C97 C98 C99 Total
    multi-casquette ?
    Actionnaire uniquement 17 10 11 11 15 16 15 10 15 11 131
    Actionnaire-adhérent 30 43 34 31 29 32 30 42 34 29 334
    Actionnaire-donateur 17 14 18 9 16 14 10 6 15 21 140
    Triple-engagement 37 33 37 49 40 38 45 43 35 40 397
    Total 101 100 100 100 100 100 100 101 99 101 1002
    In [ ]:
    Copied!
    df_col_percent = df_DMC.copy()
    df_col_percent = df_col_percent.div(df_col_percent.loc['Total']) * 100
    df_col_percent = df_col_percent.round(1)
    df_col_percent.iloc[-1] = df_col_percent.iloc[:-1].sum() 
    df_col_percent
    
    df_col_percent = df_DMC.copy() df_col_percent = df_col_percent.div(df_col_percent.loc['Total']) * 100 df_col_percent = df_col_percent.round(1) df_col_percent.iloc[-1] = df_col_percent.iloc[:-1].sum() df_col_percent
    Out[ ]:
    catégories centiles actionnaires C90 C91 C92 C93 C94 C95 C96 C97 C98 C99 Total
    multi-casquette ?
    Actionnaire uniquement 16.8 10.0 11.0 11.0 15.0 16.0 15.0 9.9 15.2 10.9 13.1
    Actionnaire-adhérent 29.7 43.0 34.0 31.0 29.0 32.0 30.0 41.6 34.3 28.7 33.3
    Actionnaire-donateur 16.8 14.0 18.0 9.0 16.0 14.0 10.0 5.9 15.2 20.8 14.0
    Triple-engagement 36.6 33.0 37.0 49.0 40.0 38.0 45.0 42.6 35.4 39.6 39.6
    Total 99.9 100.0 100.0 100.0 100.0 100.0 100.0 100.0 100.1 100.0 100.0
    In [ ]:
    Copied!
    df_row_percent = df_DMC.copy()
    df_row_percent.iloc[:, :-1] = df_row_percent.iloc[:, :-1].div(df_row_percent['Total'], axis=0) * 100
    df_row_percent = df_row_percent.round(1)
    df_row_percent['Total'] = df_row_percent.iloc[:, :-1].sum(axis=1) 
    df_row_percent
    
    df_row_percent = df_DMC.copy() df_row_percent.iloc[:, :-1] = df_row_percent.iloc[:, :-1].div(df_row_percent['Total'], axis=0) * 100 df_row_percent = df_row_percent.round(1) df_row_percent['Total'] = df_row_percent.iloc[:, :-1].sum(axis=1) df_row_percent
    Out[ ]:
    catégories centiles actionnaires C90 C91 C92 C93 C94 C95 C96 C97 C98 C99 Total
    multi-casquette ?
    Actionnaire uniquement 13.0 7.6 8.4 8.4 11.5 12.2 11.5 7.6 11.5 8.4 100.1
    Actionnaire-adhérent 9.0 12.9 10.2 9.3 8.7 9.6 9.0 12.6 10.2 8.7 100.2
    Actionnaire-donateur 12.1 10.0 12.9 6.4 11.4 10.0 7.1 4.3 10.7 15.0 99.9
    Triple-engagement 9.3 8.3 9.3 12.3 10.1 9.6 11.3 10.8 8.8 10.1 99.9
    Total 10.1 10.0 10.0 10.0 10.0 10.0 10.0 10.1 9.9 10.1 100.2
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Répartition des aciennetés au sein du 10eme décile </h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Répartition des aciennetés au sein du 10eme décile

    "))

    Répartition des aciennetés au sein du 10eme décile

    In [ ]:
    Copied!
    custom_order = ['Nouvel actionnaire depuis 2017 ou plus', 'Nouvel actionnaire entre 2012 à 2017', 'Nouvel actionnaire en 2012 ou moins', "Total"]
    df_Dancienneté = df_Dancienneté.reindex(custom_order)
    df_Dancienneté
    
    custom_order = ['Nouvel actionnaire depuis 2017 ou plus', 'Nouvel actionnaire entre 2012 à 2017', 'Nouvel actionnaire en 2012 ou moins', "Total"] df_Dancienneté = df_Dancienneté.reindex(custom_order) df_Dancienneté
    Out[ ]:
    catégories centiles actionnaires C90 C91 C92 C93 C94 C95 C96 C97 C98 C99 Total
    ancienneté actionnaires
    Nouvel actionnaire depuis 2017 ou plus 36 31 33 40 31 35 29 32 47 33 347
    Nouvel actionnaire entre 2012 à 2017 31 31 33 26 29 36 38 31 22 28 305
    Nouvel actionnaire en 2012 ou moins 34 38 34 34 40 29 33 38 30 40 350
    Total 101 100 100 100 100 100 100 101 99 101 1002
    In [ ]:
    Copied!
    df_Dancienneté
    
    df_Dancienneté
    Out[ ]:
    catégories centiles actionnaires C90 C91 C92 C93 C94 C95 C96 C97 C98 C99 Total
    ancienneté actionnaires
    Nouvel actionnaire depuis 2017 ou plus 36 31 33 40 31 35 29 32 47 33 347
    Nouvel actionnaire entre 2012 à 2017 31 31 33 26 29 36 38 31 22 28 305
    Nouvel actionnaire en 2012 ou moins 34 38 34 34 40 29 33 38 30 40 350
    Total 101 100 100 100 100 100 100 101 99 101 1002
    In [ ]:
    Copied!
    df_col_percent = df_Dancienneté.copy()
    df_col_percent = df_col_percent.div(df_col_percent.loc['Total']) * 100
    df_col_percent = df_col_percent.round(0)
    df_col_percent.iloc[-1] = df_col_percent.iloc[:-1].sum() 
    df_col_percent
    
    df_col_percent = df_Dancienneté.copy() df_col_percent = df_col_percent.div(df_col_percent.loc['Total']) * 100 df_col_percent = df_col_percent.round(0) df_col_percent.iloc[-1] = df_col_percent.iloc[:-1].sum() df_col_percent
    Out[ ]:
    catégories centiles actionnaires C90 C91 C92 C93 C94 C95 C96 C97 C98 C99 Total
    ancienneté actionnaires
    Nouvel actionnaire depuis 2017 ou plus 36.0 31.0 33.0 40.0 31.0 35.0 29.0 32.0 47.0 33.0 35.0
    Nouvel actionnaire entre 2012 à 2017 31.0 31.0 33.0 26.0 29.0 36.0 38.0 31.0 22.0 28.0 30.0
    Nouvel actionnaire en 2012 ou moins 34.0 38.0 34.0 34.0 40.0 29.0 33.0 38.0 30.0 40.0 35.0
    Total 101.0 100.0 100.0 100.0 100.0 100.0 100.0 101.0 99.0 101.0 100.0
    In [ ]:
    Copied!
    custom_order = ['Nouvel actionnaire depuis 2017 ou plus', 'Nouvel actionnaire entre 2012 à 2017', 'Nouvel actionnaire en 2012 ou moins']
    df_row_percent = df_Dancienneté.copy()
    df_row_percent.iloc[:, :-1] = df_row_percent.iloc[:, :-1].div(df_row_percent['Total'], axis=0) * 100
    df_row_percent = df_row_percent.round(1)
    df_row_percent['Total'] = df_row_percent.iloc[:, :-1].sum(axis=1) 
    df_row_percent 
    
    custom_order = ['Nouvel actionnaire depuis 2017 ou plus', 'Nouvel actionnaire entre 2012 à 2017', 'Nouvel actionnaire en 2012 ou moins'] df_row_percent = df_Dancienneté.copy() df_row_percent.iloc[:, :-1] = df_row_percent.iloc[:, :-1].div(df_row_percent['Total'], axis=0) * 100 df_row_percent = df_row_percent.round(1) df_row_percent['Total'] = df_row_percent.iloc[:, :-1].sum(axis=1) df_row_percent
    Out[ ]:
    catégories centiles actionnaires C90 C91 C92 C93 C94 C95 C96 C97 C98 C99 Total
    ancienneté actionnaires
    Nouvel actionnaire depuis 2017 ou plus 10.4 8.9 9.5 11.5 8.9 10.1 8.4 9.2 13.5 9.5 99.9
    Nouvel actionnaire entre 2012 à 2017 10.2 10.2 10.8 8.5 9.5 11.8 12.5 10.2 7.2 9.2 100.1
    Nouvel actionnaire en 2012 ou moins 9.7 10.9 9.7 9.7 11.4 8.3 9.4 10.9 8.6 11.4 100.0
    Total 10.1 10.0 10.0 10.0 10.0 10.0 10.0 10.1 9.9 10.1 100.2
    In [ ]:
    Copied!
    from IPython.display import display, HTML
    
    display(HTML("<div style='page-break-before: always;'></div>"))
    
    
    # Afficher un titre centré avec une taille de police plus grande
    display(HTML('<center><h2><u>Analyse sur les dons d\'actions</u></h2></center>'))
    
    from IPython.display import display, HTML display(HTML("
    ")) # Afficher un titre centré avec une taille de police plus grande display(HTML('

    Analyse sur les dons d\'actions

    '))

    Analyse sur les dons d'actions

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Ne concerne que les personnes ayant fait des dons</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Ne concerne que les personnes ayant fait des dons

    "))

    Ne concerne que les personnes ayant fait des dons

    In [ ]:
    Copied!
    df_nbaction = df2.groupby("ID du contact")["Nombre d'actions à l'acquisition"].sum().to_frame().reset_index()
    df_don = df[df["Nature du mouvement"] =="Don TDL"]
    df_don = df_don.groupby("ID du contact")["Nombre d'actions échangées"].sum().to_frame().reset_index()
    df_don = pd.merge(df_don, df_nbaction[['ID du contact', 'Nombre d\'actions à l\'acquisition']], on='ID du contact')
    df_don["pourcentage donné"] = df_don["Nombre d'actions échangées"]/df_don["Nombre d'actions à l'acquisition"] * 100
    
    df_nbaction = df2.groupby("ID du contact")["Nombre d'actions à l'acquisition"].sum().to_frame().reset_index() df_don = df[df["Nature du mouvement"] =="Don TDL"] df_don = df_don.groupby("ID du contact")["Nombre d'actions échangées"].sum().to_frame().reset_index() df_don = pd.merge(df_don, df_nbaction[['ID du contact', 'Nombre d\'actions à l\'acquisition']], on='ID du contact') df_don["pourcentage donné"] = df_don["Nombre d'actions échangées"]/df_don["Nombre d'actions à l'acquisition"] * 100
    In [ ]:
    Copied!
    conditions = [
        (df_don["pourcentage donné"] < 20),
        (df_don["pourcentage donné"] < 40),
        (df_don["pourcentage donné"] < 60),
        (df_don['pourcentage donné'] < 80),
        (df_don['pourcentage donné'] < 100)
    ]
    
    choices = [
        "]0-20[ % d'actions données sur le total d'actions possédées",
        "[20 - 40[ % d'actions données sur le total d'actions possédées",
        "[40 - 60[ % d'actions données sur le total d'actions possédées",
        "[60 - 80[ % d'actions données sur le total d'actions possédées",
        "[80 - 100[ % d'actions données sur le total d'actions possédées"
    ]
    
    df_don["catégories des doneurs d'actions"] = np.select(conditions, choices, default="100 % d'actions données sur le total d'actions possédées")
    
    conditions = [ (df_don["pourcentage donné"] < 20), (df_don["pourcentage donné"] < 40), (df_don["pourcentage donné"] < 60), (df_don['pourcentage donné'] < 80), (df_don['pourcentage donné'] < 100) ] choices = [ "]0-20[ % d'actions données sur le total d'actions possédées", "[20 - 40[ % d'actions données sur le total d'actions possédées", "[40 - 60[ % d'actions données sur le total d'actions possédées", "[60 - 80[ % d'actions données sur le total d'actions possédées", "[80 - 100[ % d'actions données sur le total d'actions possédées" ] df_don["catégories des doneurs d'actions"] = np.select(conditions, choices, default="100 % d'actions données sur le total d'actions possédées")
    In [ ]:
    Copied!
    value_counts = df_don["catégories des doneurs d'actions"].value_counts().reset_index()
    value_counts.columns = ["catégories des doneurs d'actions", "Nombre d'individus"]
    categories_order = [ 
         "]0-20[ % d'actions données sur le total d'actions possédées",
        "[20 - 40[ % d'actions données sur le total d'actions possédées",
        "[40 - 60[ % d'actions données sur le total d'actions possédées",
        "[60 - 80[ % d'actions données sur le total d'actions possédées",
        "[80 - 100[ % d'actions données sur le total d'actions possédées",
        "100 % d'actions données sur le total d'actions possédées"]
    # Créer un DataFrame contenant toutes les catégories dans l'ordre spécifié
    categories_df = pd.DataFrame({"catégories des doneurs d'actions": categories_order})
    
    # Fusionner les données avec la réindexation
    value_counts_sorted = categories_df.merge(value_counts, how="left")
    
    value_counts["catégories des doneurs d'actions"] = value_counts["catégories des doneurs d'actions"].astype(str)
    
    # Fusionner les données avec la réindexation
    value_counts_sorted = categories_df.merge(value_counts, how="left")
    
    value_counts = df_don["catégories des doneurs d'actions"].value_counts().reset_index() value_counts.columns = ["catégories des doneurs d'actions", "Nombre d'individus"] categories_order = [ "]0-20[ % d'actions données sur le total d'actions possédées", "[20 - 40[ % d'actions données sur le total d'actions possédées", "[40 - 60[ % d'actions données sur le total d'actions possédées", "[60 - 80[ % d'actions données sur le total d'actions possédées", "[80 - 100[ % d'actions données sur le total d'actions possédées", "100 % d'actions données sur le total d'actions possédées"] # Créer un DataFrame contenant toutes les catégories dans l'ordre spécifié categories_df = pd.DataFrame({"catégories des doneurs d'actions": categories_order}) # Fusionner les données avec la réindexation value_counts_sorted = categories_df.merge(value_counts, how="left") value_counts["catégories des doneurs d'actions"] = value_counts["catégories des doneurs d'actions"].astype(str) # Fusionner les données avec la réindexation value_counts_sorted = categories_df.merge(value_counts, how="left")
    In [ ]:
    Copied!
    import matplotlib.pyplot as plt
    
    # Données pour l'histogramme
    categories = value_counts_sorted["catégories des doneurs d'actions"]
    counts = value_counts_sorted["Nombre d'individus"]
    
    # Créer le graphique
    plt.figure(figsize=(8, 6))
    bars = plt.bar(categories, counts)
    
    # Incliner les noms des catégories et espacer les barres
    plt.xticks(rotation=45, ha='right')
    
    # Titre et étiquettes des axes
    plt.title("Nombre d'individus appartenant aux différentes catégories des donateurs d'actions ")
    plt.xlabel("")
    plt.ylabel("Nombre d'individus")
    
    # Ajouter les valeurs au-dessus de chaque barre
    for bar in bars:
        height = bar.get_height()
        plt.text(bar.get_x() + bar.get_width() / 2, height, height, ha='center', va='bottom')
    
    # Afficher l'histogramme
    plt.show()
    
    import matplotlib.pyplot as plt # Données pour l'histogramme categories = value_counts_sorted["catégories des doneurs d'actions"] counts = value_counts_sorted["Nombre d'individus"] # Créer le graphique plt.figure(figsize=(8, 6)) bars = plt.bar(categories, counts) # Incliner les noms des catégories et espacer les barres plt.xticks(rotation=45, ha='right') # Titre et étiquettes des axes plt.title("Nombre d'individus appartenant aux différentes catégories des donateurs d'actions ") plt.xlabel("") plt.ylabel("Nombre d'individus") # Ajouter les valeurs au-dessus de chaque barre for bar in bars: height = bar.get_height() plt.text(bar.get_x() + bar.get_width() / 2, height, height, ha='center', va='bottom') # Afficher l'histogramme plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Clé de lecture : Parmi les souscripteurs qui ont fait des dons d'actions, il y en avait 309 qui ont donné toutes les actions qu'ils avaient achetées et 13 personnes ont donné 80 à 99 % de toutes les actions qu'ils possédaient ([80 - 100[ % d'actions données)</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Clé de lecture : Parmi les souscripteurs qui ont fait des dons d'actions, il y en avait 309 qui ont donné toutes les actions qu'ils avaient achetées et 13 personnes ont donné 80 à 99 % de toutes les actions qu'ils possédaient ([80 - 100[ % d'actions données)

    "))

    Clé de lecture : Parmi les souscripteurs qui ont fait des dons d'actions, il y en avait 309 qui ont donné toutes les actions qu'ils avaient achetées et 13 personnes ont donné 80 à 99 % de toutes les actions qu'ils possédaient ([80 - 100[ % d'actions données)

    In [ ]:
    Copied!
    import matplotlib.pyplot as plt
    
    # Récupérer les données pour le diagramme
    categories = value_counts_sorted["catégories des doneurs d'actions"]
    counts = value_counts_sorted["Nombre d'individus"]
    
    # Créer une figure et des axes
    fig, ax = plt.subplots()
    
    # Définir l'angle de départ du premier secteur (en degrés)
    startangle = 260
    
    # Générer le diagramme en secteurs avec angle de départ spécifié
    pie = ax.pie(counts, labels=categories, autopct='%1.1f%%', startangle=startangle)
    
    # Tourner le cercle
    ax.set_aspect('equal')
    
    # Ajouter un titre
    ax.set_title("Répartition des donateurs d'actions par catégorie")
    
    # Afficher le diagramme
    plt.show()
    
    import matplotlib.pyplot as plt # Récupérer les données pour le diagramme categories = value_counts_sorted["catégories des doneurs d'actions"] counts = value_counts_sorted["Nombre d'individus"] # Créer une figure et des axes fig, ax = plt.subplots() # Définir l'angle de départ du premier secteur (en degrés) startangle = 260 # Générer le diagramme en secteurs avec angle de départ spécifié pie = ax.pie(counts, labels=categories, autopct='%1.1f%%', startangle=startangle) # Tourner le cercle ax.set_aspect('equal') # Ajouter un titre ax.set_title("Répartition des donateurs d'actions par catégorie") # Afficher le diagramme plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    df_don = df_don.merge(df[["Catégories souscripteurs","multi-casquette ?","ancienneté actionnaires","catégories âge", "ID du contact"]], on='ID du contact', how='left')
    df_don= df_don.drop_duplicates(subset="ID du contact")
    # Définir les conditions pour les catégories d'actions possédées
    conditions = [
        (df_don["Nombre d'actions à l'acquisition"] <= 10),
        (df_don["Nombre d'actions à l'acquisition"] <= 50),
        (df_don["Nombre d'actions à l'acquisition"] <= 200)
    ]
    
    # Définir les valeurs correspondantes pour chaque condition
    values = ['1 à 10 actions possédées', '11 à 50 actions possédées', '51 à 200 actions possédées']
    
    # Appliquer les conditions et attribuer les valeurs correspondantes à la nouvelle colonne
    df_don["catégorie actionnaire par nombre d'actions"] = np.select(conditions, values, default='Plus de 200 actions possédées')
    
    df_don = df_don.merge(df[["Catégories souscripteurs","multi-casquette ?","ancienneté actionnaires","catégories âge", "ID du contact"]], on='ID du contact', how='left') df_don= df_don.drop_duplicates(subset="ID du contact") # Définir les conditions pour les catégories d'actions possédées conditions = [ (df_don["Nombre d'actions à l'acquisition"] <= 10), (df_don["Nombre d'actions à l'acquisition"] <= 50), (df_don["Nombre d'actions à l'acquisition"] <= 200) ] # Définir les valeurs correspondantes pour chaque condition values = ['1 à 10 actions possédées', '11 à 50 actions possédées', '51 à 200 actions possédées'] # Appliquer les conditions et attribuer les valeurs correspondantes à la nouvelle colonne df_don["catégorie actionnaire par nombre d'actions"] = np.select(conditions, values, default='Plus de 200 actions possédées')
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Croisement entre les caractérisitiques des donateurs et le pourcentage des leurs actions données</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Croisement entre les caractérisitiques des donateurs et le pourcentage des leurs actions données

    "))

    Croisement entre les caractérisitiques des donateurs et le pourcentage des leurs actions données

    In [ ]:
    Copied!
    categories_order = [ 
         "]0-20[ % d'actions données sur le total d'actions possédées",
        "[20 - 40[ % d'actions données sur le total d'actions possédées",
        "[40 - 60[ % d'actions données sur le total d'actions possédées",
        "[60 - 80[ % d'actions données sur le total d'actions possédées",
        "[80 - 100[ % d'actions données sur le total d'actions possédées",
        "100 % d'actions données sur le total d'actions possédées",
        "Total"]
    
    categories_order = [ "]0-20[ % d'actions données sur le total d'actions possédées", "[20 - 40[ % d'actions données sur le total d'actions possédées", "[40 - 60[ % d'actions données sur le total d'actions possédées", "[60 - 80[ % d'actions données sur le total d'actions possédées", "[80 - 100[ % d'actions données sur le total d'actions possédées", "100 % d'actions données sur le total d'actions possédées", "Total"]
    In [ ]:
    Copied!
    df_donage = pd.crosstab(index=df_don["catégories des doneurs d'actions"], columns=df_don["catégories âge"], margins=True, margins_name='Total')
    df_donage = df_donage.reindex(categories_order)
    df_donage
    
    df_donage = pd.crosstab(index=df_don["catégories des doneurs d'actions"], columns=df_don["catégories âge"], margins=True, margins_name='Total') df_donage = df_donage.reindex(categories_order) df_donage
    Out[ ]:
    catégories âge 0-25 ans 25-40 ans 40-60 ans 60 ans et plus Total
    catégories des doneurs d'actions
    ]0-20[ % d'actions données sur le total d'actions possédées 82 45 75 112 314
    [20 - 40[ % d'actions données sur le total d'actions possédées 31 18 22 25 96
    [40 - 60[ % d'actions données sur le total d'actions possédées 16 12 7 18 53
    [60 - 80[ % d'actions données sur le total d'actions possédées 15 11 13 17 56
    [80 - 100[ % d'actions données sur le total d'actions possédées 4 2 3 8 17
    100 % d'actions données sur le total d'actions possédées 87 66 66 125 344
    Total 235 154 186 305 880
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Les actionnaires qui donnent leurs actions ont globalement plus de 60 ans</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Les actionnaires qui donnent leurs actions ont globalement plus de 60 ans

    "))

    Les actionnaires qui donnent leurs actions ont globalement plus de 60 ans

    In [ ]:
    Copied!
    df_donancieneté = pd.crosstab(index=df_don["catégories des doneurs d'actions"], columns=df_don["ancienneté actionnaires"], margins=True, margins_name='Total')
    df_donancieneté.reindex(categories_order)
    
    df_donancieneté = pd.crosstab(index=df_don["catégories des doneurs d'actions"], columns=df_don["ancienneté actionnaires"], margins=True, margins_name='Total') df_donancieneté.reindex(categories_order)
    Out[ ]:
    ancienneté actionnaires Nouvel actionnaire depuis 2017 ou plus Nouvel actionnaire en 2012 ou moins Nouvel actionnaire entre 2012 à 2017 Total
    catégories des doneurs d'actions
    ]0-20[ % d'actions données sur le total d'actions possédées 112 107 95 314
    [20 - 40[ % d'actions données sur le total d'actions possédées 44 32 20 96
    [40 - 60[ % d'actions données sur le total d'actions possédées 17 22 14 53
    [60 - 80[ % d'actions données sur le total d'actions possédées 16 18 22 56
    [80 - 100[ % d'actions données sur le total d'actions possédées 6 10 1 17
    100 % d'actions données sur le total d'actions possédées 110 136 98 344
    Total 305 325 250 880
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>Les actionnaires qui donnent leurs actions sont globalement anciens</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Les actionnaires qui donnent leurs actions sont globalement anciens

    "))

    Les actionnaires qui donnent leurs actions sont globalement anciens

    In [ ]:
    Copied!
    df_donMC = pd.crosstab(index=df_don["catégories des doneurs d'actions"], columns=df_don["multi-casquette ?"], margins=True, margins_name='Total')
    df_donMC.reindex(categories_order)
    
    df_donMC = pd.crosstab(index=df_don["catégories des doneurs d'actions"], columns=df_don["multi-casquette ?"], margins=True, margins_name='Total') df_donMC.reindex(categories_order)
    Out[ ]:
    multi-casquette ? Actionnaire uniquement Actionnaire-adhérent Actionnaire-donateur Triple-engagement Total
    catégories des doneurs d'actions
    ]0-20[ % d'actions données sur le total d'actions possédées 88 98 35 93 314
    [20 - 40[ % d'actions données sur le total d'actions possédées 20 21 14 41 96
    [40 - 60[ % d'actions données sur le total d'actions possédées 11 16 6 20 53
    [60 - 80[ % d'actions données sur le total d'actions possédées 18 8 5 25 56
    [80 - 100[ % d'actions données sur le total d'actions possédées 1 8 2 6 17
    100 % d'actions données sur le total d'actions possédées 84 104 37 119 344
    Total 222 255 99 304 880
    In [ ]:
    Copied!
    df_donMS = pd.crosstab(index=df_don["catégories des doneurs d'actions"], columns=df_don["Catégories souscripteurs"], margins=True, margins_name='Total')
    df_donMS.reindex(categories_order)
    
    df_donMS = pd.crosstab(index=df_don["catégories des doneurs d'actions"], columns=df_don["Catégories souscripteurs"], margins=True, margins_name='Total') df_donMS.reindex(categories_order)
    Out[ ]:
    Catégories souscripteurs 1 souscription 10 souscriptions et plus 2 souscriptions 3 à 5 souscriptions 6 à 10 souscriptions Total
    catégories des doneurs d'actions
    ]0-20[ % d'actions données sur le total d'actions possédées 131 7 86 57 33 314
    [20 - 40[ % d'actions données sur le total d'actions possédées 51 1 22 14 8 96
    [40 - 60[ % d'actions données sur le total d'actions possédées 33 0 14 4 2 53
    [60 - 80[ % d'actions données sur le total d'actions possédées 32 1 18 4 1 56
    [80 - 100[ % d'actions données sur le total d'actions possédées 11 0 3 2 1 17
    100 % d'actions données sur le total d'actions possédées 271 0 56 12 5 344
    Total 529 9 199 93 50 880
    In [ ]:
    Copied!
    df_donnbactions = pd.crosstab(index=df_don["catégories des doneurs d'actions"], columns=df_don["catégorie actionnaire par nombre d'actions"], margins=True, margins_name='Total')
    df_donnbactions.reindex(categories_order)
    
    df_donnbactions = pd.crosstab(index=df_don["catégories des doneurs d'actions"], columns=df_don["catégorie actionnaire par nombre d'actions"], margins=True, margins_name='Total') df_donnbactions.reindex(categories_order)
    Out[ ]:
    catégorie actionnaire par nombre d'actions 1 à 10 actions possédées 11 à 50 actions possédées 51 à 200 actions possédées Plus de 200 actions possédées Total
    catégories des doneurs d'actions
    ]0-20[ % d'actions données sur le total d'actions possédées 16 56 113 129 314
    [20 - 40[ % d'actions données sur le total d'actions possédées 20 38 25 13 96
    [40 - 60[ % d'actions données sur le total d'actions possédées 12 19 20 2 53
    [60 - 80[ % d'actions données sur le total d'actions possédées 19 11 21 5 56
    [80 - 100[ % d'actions données sur le total d'actions possédées 7 5 5 0 17
    100 % d'actions données sur le total d'actions possédées 217 80 36 11 344
    Total 291 209 220 160 880
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h3>50% de ceux qui donnent totalement leurs actions en ont peu</h3>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    50% de ceux qui donnent totalement leurs actions en ont peu

    "))

    50% de ceux qui donnent totalement leurs actions en ont peu

    In [ ]:
    Copied!
    from IPython.display import display, HTML
    
    display(HTML("<div style='page-break-before: always;'></div>"))
    
    # Afficher un titre centré avec une taille de police plus grande
    display(HTML('<center><u><h2>Analyses statistiques</u></h2></center>')) 
    
    from IPython.display import display, HTML display(HTML("
    ")) # Afficher un titre centré avec une taille de police plus grande display(HTML('

    Analyses statistiques

    '))

    Analyses statistiques

    In [ ]:
    Copied!
    from IPython.display import display, HTML
    
    display(HTML("<div style='page-break-before: always;'></div>"))
    
    # Afficher un titre centré avec une taille de police plus grande
    display(HTML('<center><h2>Les commentaires sous les analyses statistiques peuvent ne pas être valables. Les données étant créees aléatoirement à chaque fois que le code est exécuté, les résultats des analyses sont différent à chaque fois. Laisser les commentaires permet d\'éclairer sur les méthodes de lecture et de compréhension des analyses plutôt que s\'intéresser à leurs résultats mêmes</h2></center>'))
    
    from IPython.display import display, HTML display(HTML("
    ")) # Afficher un titre centré avec une taille de police plus grande display(HTML('

    Les commentaires sous les analyses statistiques peuvent ne pas être valables. Les données étant créees aléatoirement à chaque fois que le code est exécuté, les résultats des analyses sont différent à chaque fois. Laisser les commentaires permet d\'éclairer sur les méthodes de lecture et de compréhension des analyses plutôt que s\'intéresser à leurs résultats mêmes

    '))

    Les commentaires sous les analyses statistiques peuvent ne pas être valables. Les données étant créees aléatoirement à chaque fois que le code est exécuté, les résultats des analyses sont différent à chaque fois. Laisser les commentaires permet d'éclairer sur les méthodes de lecture et de compréhension des analyses plutôt que s'intéresser à leurs résultats mêmes

    In [ ]:
    Copied!
    df_nbaction = df2.groupby("ID du contact")["Nombre d'actions à l'acquisition"].sum().to_frame().reset_index()
    
    df_nbaction = df2.groupby("ID du contact")["Nombre d'actions à l'acquisition"].sum().to_frame().reset_index()
    In [ ]:
    Copied!
    df_nbaction= df_nbaction.merge(df[['ID du contact',"Nombre de souscriptions"]], on='ID du contact', how='left')
    df_nbaction = df_nbaction.drop_duplicates(subset="ID du contact")
    
    df_nbaction= df_nbaction.merge(df[['ID du contact',"Nombre de souscriptions"]], on='ID du contact', how='left') df_nbaction = df_nbaction.drop_duplicates(subset="ID du contact")
    In [ ]:
    Copied!
    df_diff_mean = df_diff_mean.merge(df_nbaction[["ID du contact","Nombre d'actions à l'acquisition","Nombre de souscriptions"]], on='ID du contact', how='left')
    df_diff_mean = df_diff_mean.drop_duplicates(subset="ID du contact")
    df_diff_mean["Nombre moyen d'action par souscription"] = df_diff_mean["Nombre d'actions à l'acquisition"]/df_diff_mean["Nombre de souscriptions"]
    
    df_diff_mean = df_diff_mean.merge(df_nbaction[["ID du contact","Nombre d'actions à l'acquisition","Nombre de souscriptions"]], on='ID du contact', how='left') df_diff_mean = df_diff_mean.drop_duplicates(subset="ID du contact") df_diff_mean["Nombre moyen d'action par souscription"] = df_diff_mean["Nombre d'actions à l'acquisition"]/df_diff_mean["Nombre de souscriptions"]
    In [ ]:
    Copied!
    import pandas as pd
    import statsmodels.api as sm
    import matplotlib.pyplot as plt
    
    # Charger les données à partir du DataFrame donné (merged_dffinalMS)
    dfa = df_diff_mean.copy()
    
    # Supprimer les lignes où la variable "Nombre moyen d'action par souscription" dépasse 300
    dfa = dfa.drop(dfa[dfa["Nombre moyen d'action par souscription"] > 300].index)
    
    # Supprimer les lignes avec des valeurs manquantes pour la variable 'Moyenne temps pour nouvelle resouscription'
    dfa = dfa.dropna(subset=['Différence'])
    
    # Vérifier le nombre de lignes après la suppression des valeurs manquantes
    print("Nombre de lignes après suppression des valeurs manquantes :", len(dfa))
    
    
    # Définir les variables dépendante (y) et indépendante (x)
    y = dfa["Différence"]
    x = dfa["Nombre moyen d'action par souscription"]
    
    # Ajouter une constante à la variable indépendante
    x = sm.add_constant(x)
    
    # Créer un modèle de régression linéaire et ajuster aux données avec covariance robuste (HC3)
    model = sm.OLS(y, x)
    results = model.fit(cov_type='HC3')
    
    # Afficher les résultats de la régression avec covariance robuste
    print(results.summary())
    
    # Plot des données avec la ligne de régression
    plt.scatter(dfa["Nombre moyen d'action par souscription"], dfa["Différence"])
    plt.plot(dfa["Nombre moyen d'action par souscription"], results.fittedvalues, color='red', linewidth=2)
    plt.xlabel("Nombre moyen d'action par souscription")
    plt.ylabel("Moyenne temps pour nouvelle resouscription")
    plt.title("Régression linéaire du temps moyen pour nouvelle resouscription par rapport au nombre moyen d'actions par souscription")
    plt.show()
    
    import pandas as pd import statsmodels.api as sm import matplotlib.pyplot as plt # Charger les données à partir du DataFrame donné (merged_dffinalMS) dfa = df_diff_mean.copy() # Supprimer les lignes où la variable "Nombre moyen d'action par souscription" dépasse 300 dfa = dfa.drop(dfa[dfa["Nombre moyen d'action par souscription"] > 300].index) # Supprimer les lignes avec des valeurs manquantes pour la variable 'Moyenne temps pour nouvelle resouscription' dfa = dfa.dropna(subset=['Différence']) # Vérifier le nombre de lignes après la suppression des valeurs manquantes print("Nombre de lignes après suppression des valeurs manquantes :", len(dfa)) # Définir les variables dépendante (y) et indépendante (x) y = dfa["Différence"] x = dfa["Nombre moyen d'action par souscription"] # Ajouter une constante à la variable indépendante x = sm.add_constant(x) # Créer un modèle de régression linéaire et ajuster aux données avec covariance robuste (HC3) model = sm.OLS(y, x) results = model.fit(cov_type='HC3') # Afficher les résultats de la régression avec covariance robuste print(results.summary()) # Plot des données avec la ligne de régression plt.scatter(dfa["Nombre moyen d'action par souscription"], dfa["Différence"]) plt.plot(dfa["Nombre moyen d'action par souscription"], results.fittedvalues, color='red', linewidth=2) plt.xlabel("Nombre moyen d'action par souscription") plt.ylabel("Moyenne temps pour nouvelle resouscription") plt.title("Régression linéaire du temps moyen pour nouvelle resouscription par rapport au nombre moyen d'actions par souscription") plt.show()
    Nombre de lignes après suppression des valeurs manquantes : 4125
                                OLS Regression Results                            
    ==============================================================================
    Dep. Variable:             Différence   R-squared:                       0.000
    Model:                            OLS   Adj. R-squared:                 -0.000
    Method:                 Least Squares   F-statistic:                    0.3046
    Date:                Thu, 28 Sep 2023   Prob (F-statistic):              0.581
    Time:                        14:13:29   Log-Likelihood:                -9888.6
    No. Observations:                4125   AIC:                         1.978e+04
    Df Residuals:                    4123   BIC:                         1.979e+04
    Df Model:                           1                                         
    Covariance Type:                  HC3                                         
    ==========================================================================================================
                                                 coef    std err          z      P>|z|      [0.025      0.975]
    ----------------------------------------------------------------------------------------------------------
    const                                      2.8386      0.056     51.019      0.000       2.730       2.948
    Nombre moyen d'action par souscription    -0.0004      0.001     -0.552      0.581      -0.002       0.001
    ==============================================================================
    Omnibus:                     1173.394   Durbin-Watson:                   1.994
    Prob(Omnibus):                  0.000   Jarque-Bera (JB):             2839.260
    Skew:                           1.579   Prob(JB):                         0.00
    Kurtosis:                       5.560   Cond. No.                         104.
    ==============================================================================
    
    Notes:
    [1] Standard Errors are heteroscedasticity robust (HC3)
    
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Clé de lecture : Il y a peu de lien entre le laps de temps pour reprendre une souscription et le nombre moyen d'actions prises par souscription. On remarque que la ligne rouge est presque horizontale. Alors que plus cette dernière est verticale plus il y a une corrélation forte entre les 2 variables. De plus si la ligne monte vers le ciel, il y a une corrélation positive et inversement. Ici on remarque que la ligne plonge. On remarque que les personnes qui ont pris beaucoup d'actions par souscription en moyenne ont tendance à reprendre des souscriptions de manière moins espacée. Le fait d'avoir une moyenne d'actions par souscription avec une unité en moins diminurait 0.0020 fois le laps de temps pour reprendre une souscription</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Clé de lecture : Il y a peu de lien entre le laps de temps pour reprendre une souscription et le nombre moyen d'actions prises par souscription. On remarque que la ligne rouge est presque horizontale. Alors que plus cette dernière est verticale plus il y a une corrélation forte entre les 2 variables. De plus si la ligne monte vers le ciel, il y a une corrélation positive et inversement. Ici on remarque que la ligne plonge. On remarque que les personnes qui ont pris beaucoup d'actions par souscription en moyenne ont tendance à reprendre des souscriptions de manière moins espacée. Le fait d'avoir une moyenne d'actions par souscription avec une unité en moins diminurait 0.0020 fois le laps de temps pour reprendre une souscription

    "))

    Clé de lecture : Il y a peu de lien entre le laps de temps pour reprendre une souscription et le nombre moyen d'actions prises par souscription. On remarque que la ligne rouge est presque horizontale. Alors que plus cette dernière est verticale plus il y a une corrélation forte entre les 2 variables. De plus si la ligne monte vers le ciel, il y a une corrélation positive et inversement. Ici on remarque que la ligne plonge. On remarque que les personnes qui ont pris beaucoup d'actions par souscription en moyenne ont tendance à reprendre des souscriptions de manière moins espacée. Le fait d'avoir une moyenne d'actions par souscription avec une unité en moins diminurait 0.0020 fois le laps de temps pour reprendre une souscription

    In [ ]:
    Copied!
    from datetime import datetime, timedelta
    df_durée_conserv = df[df["Nature du mouvement"] == "Rachat"]
    df_durée_conserv = df_durée_conserv.groupby("ID du contact")["durée conservation"].mean().to_frame().reset_index()
    df_durée_conserv = df_durée_conserv.drop(df_durée_conserv[df_durée_conserv["durée conservation"] < timedelta(days=0)].index)
    df_durée_conserv = df_durée_conserv.merge(df_nbaction[["ID du contact","Nombre d'actions à l'acquisition","Nombre de souscriptions"]], on='ID du contact', how='left')
    df_durée_conserv = df_durée_conserv.drop_duplicates(subset="ID du contact")
    df_durée_conserv["Nombre moyen d'action par souscription"] = df_durée_conserv["Nombre d'actions à l'acquisition"]/df_durée_conserv["Nombre de souscriptions"]
    
    from datetime import datetime, timedelta df_durée_conserv = df[df["Nature du mouvement"] == "Rachat"] df_durée_conserv = df_durée_conserv.groupby("ID du contact")["durée conservation"].mean().to_frame().reset_index() df_durée_conserv = df_durée_conserv.drop(df_durée_conserv[df_durée_conserv["durée conservation"] < timedelta(days=0)].index) df_durée_conserv = df_durée_conserv.merge(df_nbaction[["ID du contact","Nombre d'actions à l'acquisition","Nombre de souscriptions"]], on='ID du contact', how='left') df_durée_conserv = df_durée_conserv.drop_duplicates(subset="ID du contact") df_durée_conserv["Nombre moyen d'action par souscription"] = df_durée_conserv["Nombre d'actions à l'acquisition"]/df_durée_conserv["Nombre de souscriptions"]
    In [ ]:
    Copied!
    import pandas as pd
    import statsmodels.api as sm
    
    # Charger les données à partir du DataFrame donné (merged_dffinalMS)
    dfb = df_durée_conserv.copy()
    
    # Supprimer les lignes où la variable "Nombre moyen d'action par souscription" dépasse 300
    dfb = dfb.drop(dfb[dfb["Nombre moyen d'action par souscription"] > 300].index)
    
    # Supprimer les lignes avec des valeurs manquantes pour les variables concernées
    dfb = dfb.dropna(subset=['durée conservation', "Nombre moyen d'action par souscription"])
    
    # Convertir la variable "Moyenne temps pour nouvelle resouscription" en années (numérique)
    dfb["durée conservation"] = dfb["durée conservation"] / pd.Timedelta(days=365)
    
    # Définir les variables dépendante (y) et indépendante (x)
    y = dfb["durée conservation"]
    x = dfb["Nombre moyen d'action par souscription"]
    
    # Ajouter une constante à la variable indépendante
    x = sm.add_constant(x)
    
    # Créer un modèle de régression linéaire et ajuster aux données avec covariance robuste (HC3)
    model = sm.OLS(y, x)
    results = model.fit(cov_type='HC3')
    
    # Afficher les résultats de la régression avec covariance robuste
    print(results.summary())
    
    # Plot des données avec la ligne de régression
    plt.scatter(dfb["Nombre moyen d'action par souscription"], dfb["durée conservation"])
    plt.plot(dfb["Nombre moyen d'action par souscription"], results.fittedvalues, color='red', linewidth=2)
    plt.xlabel("Nombre moyen d'action par souscription")
    plt.ylabel("intervalle moyen entre interaction avec un contrat")
    plt.title("Régression linéaire de l'intervalle moyen  (en année) entre interaction avec un contrat par rapport au nombre moyen d'actions par souscription")
    plt.show()
    
    import pandas as pd import statsmodels.api as sm # Charger les données à partir du DataFrame donné (merged_dffinalMS) dfb = df_durée_conserv.copy() # Supprimer les lignes où la variable "Nombre moyen d'action par souscription" dépasse 300 dfb = dfb.drop(dfb[dfb["Nombre moyen d'action par souscription"] > 300].index) # Supprimer les lignes avec des valeurs manquantes pour les variables concernées dfb = dfb.dropna(subset=['durée conservation', "Nombre moyen d'action par souscription"]) # Convertir la variable "Moyenne temps pour nouvelle resouscription" en années (numérique) dfb["durée conservation"] = dfb["durée conservation"] / pd.Timedelta(days=365) # Définir les variables dépendante (y) et indépendante (x) y = dfb["durée conservation"] x = dfb["Nombre moyen d'action par souscription"] # Ajouter une constante à la variable indépendante x = sm.add_constant(x) # Créer un modèle de régression linéaire et ajuster aux données avec covariance robuste (HC3) model = sm.OLS(y, x) results = model.fit(cov_type='HC3') # Afficher les résultats de la régression avec covariance robuste print(results.summary()) # Plot des données avec la ligne de régression plt.scatter(dfb["Nombre moyen d'action par souscription"], dfb["durée conservation"]) plt.plot(dfb["Nombre moyen d'action par souscription"], results.fittedvalues, color='red', linewidth=2) plt.xlabel("Nombre moyen d'action par souscription") plt.ylabel("intervalle moyen entre interaction avec un contrat") plt.title("Régression linéaire de l'intervalle moyen (en année) entre interaction avec un contrat par rapport au nombre moyen d'actions par souscription") plt.show()
                                OLS Regression Results                            
    ==============================================================================
    Dep. Variable:     durée conservation   R-squared:                       0.000
    Model:                            OLS   Adj. R-squared:                 -0.001
    Method:                 Least Squares   F-statistic:                 4.345e-05
    Date:                Thu, 28 Sep 2023   Prob (F-statistic):              0.995
    Time:                        14:13:29   Log-Likelihood:                -3307.6
    No. Observations:                1151   AIC:                             6619.
    Df Residuals:                    1149   BIC:                             6629.
    Df Model:                           1                                         
    Covariance Type:                  HC3                                         
    ==========================================================================================================
                                                 coef    std err          z      P>|z|      [0.025      0.975]
    ----------------------------------------------------------------------------------------------------------
    const                                      6.8504      0.159     43.110      0.000       6.539       7.162
    Nombre moyen d'action par souscription -1.534e-05      0.002     -0.007      0.995      -0.005       0.005
    ==============================================================================
    Omnibus:                      178.372   Durbin-Watson:                   1.979
    Prob(Omnibus):                  0.000   Jarque-Bera (JB):               55.879
    Skew:                           0.285   Prob(JB):                     7.35e-13
    Kurtosis:                       2.084   Cond. No.                         89.8
    ==============================================================================
    
    Notes:
    [1] Standard Errors are heteroscedasticity robust (HC3)
    
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Clé de lecture : Pour le test précent, dans le tableau ''OLS Regression Results'', on observe que pour la variable ''Nombre moyen d'actions par souscription'' une valeur P>|z| a été calculée à 0.096 soit 9,6 % de chances de se tromper en affirmant qu'il puisse avoir une corrélation entre le nombre moyen d'actions par souscription par personne et le fait que cette personne ait pris plus ou moins de temps avant de faire un rachat d'actions sur un de ses contrats. Il est préférable que la valeur ''P>|z|' calculée soit inférieure à 0,05 pour pouvoir affirmer qu'il y ait un lien entre 2 variables. En plus de ne rien pouvoir affirmer sur le lien entre les 2 variables prises en compte, on voit que la relation entre ces dernières est potentiellement très faible. Une unité en plus du nombre moyen d'actions par souscriptions diminuerait de 0.0025 fois le laps de temps pour un rachat d'actions</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Clé de lecture : Pour le test précent, dans le tableau ''OLS Regression Results'', on observe que pour la variable ''Nombre moyen d'actions par souscription'' une valeur P>|z| a été calculée à 0.096 soit 9,6 % de chances de se tromper en affirmant qu'il puisse avoir une corrélation entre le nombre moyen d'actions par souscription par personne et le fait que cette personne ait pris plus ou moins de temps avant de faire un rachat d'actions sur un de ses contrats. Il est préférable que la valeur ''P>|z|' calculée soit inférieure à 0,05 pour pouvoir affirmer qu'il y ait un lien entre 2 variables. En plus de ne rien pouvoir affirmer sur le lien entre les 2 variables prises en compte, on voit que la relation entre ces dernières est potentiellement très faible. Une unité en plus du nombre moyen d'actions par souscriptions diminuerait de 0.0025 fois le laps de temps pour un rachat d'actions

    "))

    Clé de lecture : Pour le test précent, dans le tableau ''OLS Regression Results'', on observe que pour la variable ''Nombre moyen d'actions par souscription'' une valeur P>|z| a été calculée à 0.096 soit 9,6 % de chances de se tromper en affirmant qu'il puisse avoir une corrélation entre le nombre moyen d'actions par souscription par personne et le fait que cette personne ait pris plus ou moins de temps avant de faire un rachat d'actions sur un de ses contrats. Il est préférable que la valeur ''P>|z|' calculée soit inférieure à 0,05 pour pouvoir affirmer qu'il y ait un lien entre 2 variables. En plus de ne rien pouvoir affirmer sur le lien entre les 2 variables prises en compte, on voit que la relation entre ces dernières est potentiellement très faible. Une unité en plus du nombre moyen d'actions par souscriptions diminuerait de 0.0025 fois le laps de temps pour un rachat d'actions

    In [ ]:
    Copied!
    df_retraitdef =  df_retraitdef.merge(df_nbaction[["ID du contact","Nombre d'actions à l'acquisition"]], on='ID du contact', how='left')
    df_retraitdef =  df_retraitdef.drop_duplicates(subset="ID du contact")
    
    df_retraitdef = df_retraitdef.merge(df_nbaction[["ID du contact","Nombre d'actions à l'acquisition"]], on='ID du contact', how='left') df_retraitdef = df_retraitdef.drop_duplicates(subset="ID du contact")
    In [ ]:
    Copied!
    df_retraitdef["Nombre moyen d'action par souscription"] = df_retraitdef["Nombre d'actions à l'acquisition_y"]/df_retraitdef["Nombre de souscriptions"]
    
    df_retraitdef["Nombre moyen d'action par souscription"] = df_retraitdef["Nombre d'actions à l'acquisition_y"]/df_retraitdef["Nombre de souscriptions"]
    In [ ]:
    Copied!
    import pandas as pd
    import statsmodels.api as sm
    
    # Charger les données à partir du DataFrame donné (merged_dffinalMS)
    dfc = df_retraitdef.copy()
    
    # Supprimer les lignes où la variable "Nombre moyen d'action par souscription" dépasse 300
    dfc = dfc.drop(dfc[dfc["Nombre moyen d'action par souscription"] > 300].index)
    
    # Supprimer les lignes avec des valeurs manquantes pour les variables concernées
    dfc = dfc.dropna(subset=['Durée actionnariat', "Nombre moyen d'action par souscription"])
    
    
    # Définir les variables dépendante (y) et indépendante (x)
    y = dfc["Durée actionnariat"]
    x = dfc["Nombre moyen d'action par souscription"]
    
    # Ajouter une constante à la variable indépendante
    x = sm.add_constant(x)
    
    # Créer un modèle de régression linéaire et ajuster aux données avec covariance robuste (HC3)
    model = sm.OLS(y, x)
    results = model.fit(cov_type='HC3')
    
    # Afficher les résultats de la régression avec covariance robuste
    print(results.summary())
    
    # Plot des données avec la ligne de régression
    plt.scatter(dfc["Nombre moyen d'action par souscription"], dfc["Durée actionnariat"])
    plt.plot(dfc["Nombre moyen d'action par souscription"], results.fittedvalues, color='red', linewidth=2)
    plt.xlabel("Nombre moyen d'action par souscription")
    plt.ylabel("Moyenne durée actionnariat")
    plt.title("Régression linéaire de la durée de vie d'actionnaire par rapport au nombre moyen d'actions par souscription")
    plt.show()
    
    import pandas as pd import statsmodels.api as sm # Charger les données à partir du DataFrame donné (merged_dffinalMS) dfc = df_retraitdef.copy() # Supprimer les lignes où la variable "Nombre moyen d'action par souscription" dépasse 300 dfc = dfc.drop(dfc[dfc["Nombre moyen d'action par souscription"] > 300].index) # Supprimer les lignes avec des valeurs manquantes pour les variables concernées dfc = dfc.dropna(subset=['Durée actionnariat', "Nombre moyen d'action par souscription"]) # Définir les variables dépendante (y) et indépendante (x) y = dfc["Durée actionnariat"] x = dfc["Nombre moyen d'action par souscription"] # Ajouter une constante à la variable indépendante x = sm.add_constant(x) # Créer un modèle de régression linéaire et ajuster aux données avec covariance robuste (HC3) model = sm.OLS(y, x) results = model.fit(cov_type='HC3') # Afficher les résultats de la régression avec covariance robuste print(results.summary()) # Plot des données avec la ligne de régression plt.scatter(dfc["Nombre moyen d'action par souscription"], dfc["Durée actionnariat"]) plt.plot(dfc["Nombre moyen d'action par souscription"], results.fittedvalues, color='red', linewidth=2) plt.xlabel("Nombre moyen d'action par souscription") plt.ylabel("Moyenne durée actionnariat") plt.title("Régression linéaire de la durée de vie d'actionnaire par rapport au nombre moyen d'actions par souscription") plt.show()
                                OLS Regression Results                            
    ==============================================================================
    Dep. Variable:     Durée actionnariat   R-squared:                       0.001
    Model:                            OLS   Adj. R-squared:                 -0.011
    Method:                 Least Squares   F-statistic:                    0.1019
    Date:                Thu, 28 Sep 2023   Prob (F-statistic):              0.750
    Time:                        14:13:30   Log-Likelihood:                -240.34
    No. Observations:                  86   AIC:                             484.7
    Df Residuals:                      84   BIC:                             489.6
    Df Model:                           1                                         
    Covariance Type:                  HC3                                         
    ==========================================================================================================
                                                 coef    std err          z      P>|z|      [0.025      0.975]
    ----------------------------------------------------------------------------------------------------------
    const                                      7.8337      0.547     14.324      0.000       6.762       8.906
    Nombre moyen d'action par souscription     0.0025      0.008      0.319      0.750      -0.013       0.018
    ==============================================================================
    Omnibus:                        2.710   Durbin-Watson:                   1.695
    Prob(Omnibus):                  0.258   Jarque-Bera (JB):                1.906
    Skew:                           0.170   Prob(JB):                        0.386
    Kurtosis:                       2.355   Cond. No.                         73.3
    ==============================================================================
    
    Notes:
    [1] Standard Errors are heteroscedasticity robust (HC3)
    
    No description has been provided for this image
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<center><h2>ANOVA des nombres de souscriptions en fonction des retraits partiels ou non d'actions sur un contrat</h2></center>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    ANOVA des nombres de souscriptions en fonction des retraits partiels ou non d'actions sur un contrat

    "))

    ANOVA des nombres de souscriptions en fonction des retraits partiels ou non d'actions sur un contrat

    In [ ]:
    Copied!
    import pandas as pd
    import statsmodels.api as sm
    from statsmodels.formula.api import ols
    from statsmodels.stats.multicomp import pairwise_tukeyhsd
    
    # Charger les données à partir du DataFrame donné (df_actionnaireretrait)
    df = df_retrait
    # Supprimer les lignes avec des valeurs manquantes pour les variables concernées
    df = df.dropna(subset=["Nombre de souscriptions", "retrait complet ou partiel"])
    # Effectuer l'ANOVA
    model = ols('df["Nombre de souscriptions"] ~ C(df["retrait complet ou partiel"])', data=df).fit()
    anova_table = sm.stats.anova_lm(model, typ=2)
    
    # Effectuer les comparaisons post hoc (méthode de Tukey)
    posthoc = pairwise_tukeyhsd(df["Nombre de souscriptions"], df['retrait complet ou partiel'])
    
    # Afficher la table ANOVA
    print(anova_table)
    
    # Afficher les comparaisons post hoc
    print(posthoc)
    
    import pandas as pd import statsmodels.api as sm from statsmodels.formula.api import ols from statsmodels.stats.multicomp import pairwise_tukeyhsd # Charger les données à partir du DataFrame donné (df_actionnaireretrait) df = df_retrait # Supprimer les lignes avec des valeurs manquantes pour les variables concernées df = df.dropna(subset=["Nombre de souscriptions", "retrait complet ou partiel"]) # Effectuer l'ANOVA model = ols('df["Nombre de souscriptions"] ~ C(df["retrait complet ou partiel"])', data=df).fit() anova_table = sm.stats.anova_lm(model, typ=2) # Effectuer les comparaisons post hoc (méthode de Tukey) posthoc = pairwise_tukeyhsd(df["Nombre de souscriptions"], df['retrait complet ou partiel']) # Afficher la table ANOVA print(anova_table) # Afficher les comparaisons post hoc print(posthoc)
                                              sum_sq      df         F    PR(>F)
    C(df["retrait complet ou partiel"])     6.609192     1.0  1.562966  0.211398
    Residual                             7446.602379  1761.0       NaN       NaN
             Multiple Comparison of Means - Tukey HSD, FWER=0.05         
    =====================================================================
         group1          group2     meandiff p-adj   lower  upper  reject
    ---------------------------------------------------------------------
    retrait complet retrait partiel   0.1666 0.2114 -0.0947 0.4278  False
    ---------------------------------------------------------------------
    
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Clé de lecture : On peut affirmer qu'il y a un lien entre le fait de vider complètement ou pas un contrat de ses actions et le fait d'avoir plus ou moins pris de souscriptions. On remarque que la valeur ''p-adj'' (un équivalent de la valeur P>|z|) est égale à 0.009. On a 0,9 % de chance de se tromper en affirmant cela. Cependant cette relation est minime. Les personnes ayant vidé partiellement un de leurs contrats en faisant un rachat d'actions (retrait partiel) avaient en moyenne 0,65 souscription de moins que ceux qui ont vidé complètement leurs contrats. De plus la vérification du lien entre ces variables est un peu biaisée dans le sens ou une même personne aura pu faire des retraits partiels et des retraits complets à la fois  </h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Clé de lecture : On peut affirmer qu'il y a un lien entre le fait de vider complètement ou pas un contrat de ses actions et le fait d'avoir plus ou moins pris de souscriptions. On remarque que la valeur ''p-adj'' (un équivalent de la valeur P>|z|) est égale à 0.009. On a 0,9 % de chance de se tromper en affirmant cela. Cependant cette relation est minime. Les personnes ayant vidé partiellement un de leurs contrats en faisant un rachat d'actions (retrait partiel) avaient en moyenne 0,65 souscription de moins que ceux qui ont vidé complètement leurs contrats. De plus la vérification du lien entre ces variables est un peu biaisée dans le sens ou une même personne aura pu faire des retraits partiels et des retraits complets à la fois

    "))

    Clé de lecture : On peut affirmer qu'il y a un lien entre le fait de vider complètement ou pas un contrat de ses actions et le fait d'avoir plus ou moins pris de souscriptions. On remarque que la valeur ''p-adj'' (un équivalent de la valeur P>|z|) est égale à 0.009. On a 0,9 % de chance de se tromper en affirmant cela. Cependant cette relation est minime. Les personnes ayant vidé partiellement un de leurs contrats en faisant un rachat d'actions (retrait partiel) avaient en moyenne 0,65 souscription de moins que ceux qui ont vidé complètement leurs contrats. De plus la vérification du lien entre ces variables est un peu biaisée dans le sens ou une même personne aura pu faire des retraits partiels et des retraits complets à la fois

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<center><h2>ANOVA moyenne des nombres de souscriptions en fonction des retraits définitifs ou non de ses actions</h2></center>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    ANOVA moyenne des nombres de souscriptions en fonction des retraits définitifs ou non de ses actions

    "))

    ANOVA moyenne des nombres de souscriptions en fonction des retraits définitifs ou non de ses actions

    In [ ]:
    Copied!
    import pandas as pd
    import statsmodels.api as sm
    from statsmodels.formula.api import ols
    from statsmodels.stats.multicomp import pairwise_tukeyhsd
    
    # Charger les données à partir du DataFrame donné (df_actionnaireretrait)
    df = df_retrait
    # Supprimer les lignes avec des valeurs manquantes pour les variables concernées
    df = df.dropna(subset=["Nombre de souscriptions", "nature du retrait"])
    # Effectuer l'ANOVA
    model = ols('df["Nombre de souscriptions"] ~ C(df["nature du retrait"])', data=df).fit()
    anova_table = sm.stats.anova_lm(model, typ=2)
    
    # Effectuer les comparaisons post hoc (méthode de Tukey)
    posthoc = pairwise_tukeyhsd(df["Nombre de souscriptions"], df['nature du retrait'])
    
    # Afficher la table ANOVA
    print(anova_table)
    
    # Afficher les comparaisons post hoc
    print(posthoc)
    
    import pandas as pd import statsmodels.api as sm from statsmodels.formula.api import ols from statsmodels.stats.multicomp import pairwise_tukeyhsd # Charger les données à partir du DataFrame donné (df_actionnaireretrait) df = df_retrait # Supprimer les lignes avec des valeurs manquantes pour les variables concernées df = df.dropna(subset=["Nombre de souscriptions", "nature du retrait"]) # Effectuer l'ANOVA model = ols('df["Nombre de souscriptions"] ~ C(df["nature du retrait"])', data=df).fit() anova_table = sm.stats.anova_lm(model, typ=2) # Effectuer les comparaisons post hoc (méthode de Tukey) posthoc = pairwise_tukeyhsd(df["Nombre de souscriptions"], df['nature du retrait']) # Afficher la table ANOVA print(anova_table) # Afficher les comparaisons post hoc print(posthoc)
                                     sum_sq      df         F        PR(>F)
    C(df["nature du retrait"])   101.068215     1.0  24.20806  9.453356e-07
    Residual                    7352.143357  1761.0       NaN           NaN
             Multiple Comparison of Means - Tukey HSD, FWER=0.05         
    =====================================================================
          group1           group2     meandiff p-adj lower  upper  reject
    ---------------------------------------------------------------------
    retrait définitif retrait partiel   1.0822   0.0 0.6508 1.5135   True
    ---------------------------------------------------------------------
    
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Ceux qui n'ont pas fait de retrait définitif ont en moyenne 3 souscriptions de plus que ceux qui l'ont fait </h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Ceux qui n'ont pas fait de retrait définitif ont en moyenne 3 souscriptions de plus que ceux qui l'ont fait

    "))

    Ceux qui n'ont pas fait de retrait définitif ont en moyenne 3 souscriptions de plus que ceux qui l'ont fait

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<center><h2>ANOVA nombre d'actions des contrats en fonction du retrait total ou pas des actions par contrat </h2></center>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    ANOVA nombre d'actions des contrats en fonction du retrait total ou pas des actions par contrat

    "))

    ANOVA nombre d'actions des contrats en fonction du retrait total ou pas des actions par contrat

    In [ ]:
    Copied!
    df_retrait = df_retrait.merge(df_nbaction[["Nombre d\'actions à l\'acquisition", "ID du contact"]], on='ID du contact', how='left')
    df_retrait = df_retrait.drop_duplicates(subset="Mouvement de titre Name")
    df_retrait["Nombre moyen action par souscription"] = df_retrait["Nombre d\'actions à l\'acquisition_y"]/df_retrait["Nombre de souscriptions"]
    
    df_retrait = df_retrait.merge(df_nbaction[["Nombre d\'actions à l\'acquisition", "ID du contact"]], on='ID du contact', how='left') df_retrait = df_retrait.drop_duplicates(subset="Mouvement de titre Name") df_retrait["Nombre moyen action par souscription"] = df_retrait["Nombre d\'actions à l\'acquisition_y"]/df_retrait["Nombre de souscriptions"]
    In [ ]:
    Copied!
    import pandas as pd
    import statsmodels.api as sm
    from statsmodels.formula.api import ols
    from statsmodels.stats.multicomp import pairwise_tukeyhsd
    
    # Charger les données à partir du DataFrame donné (df_retrait)
    df = df_retrait
    df = df.dropna(subset=["Nombre d'actions à l'acquisition_x", 'retrait complet ou partiel'])
    
    # Effectuer l'ANOVA
    model = ols("df[\"Nombre d'actions à l'acquisition_x\"] ~ C(df['retrait complet ou partiel'])", data=df).fit()
    anova_table = sm.stats.anova_lm(model, typ=2)
    
    # Effectuer les comparaisons post hoc (méthode de Tukey)
    posthoc = pairwise_tukeyhsd(df["Nombre d'actions à l'acquisition_x"], df['retrait complet ou partiel'])
    
    # Afficher la table ANOVA
    print(anova_table)
    
    # Afficher les comparaisons post hoc
    print(posthoc)
    
    import pandas as pd import statsmodels.api as sm from statsmodels.formula.api import ols from statsmodels.stats.multicomp import pairwise_tukeyhsd # Charger les données à partir du DataFrame donné (df_retrait) df = df_retrait df = df.dropna(subset=["Nombre d'actions à l'acquisition_x", 'retrait complet ou partiel']) # Effectuer l'ANOVA model = ols("df[\"Nombre d'actions à l'acquisition_x\"] ~ C(df['retrait complet ou partiel'])", data=df).fit() anova_table = sm.stats.anova_lm(model, typ=2) # Effectuer les comparaisons post hoc (méthode de Tukey) posthoc = pairwise_tukeyhsd(df["Nombre d'actions à l'acquisition_x"], df['retrait complet ou partiel']) # Afficher la table ANOVA print(anova_table) # Afficher les comparaisons post hoc print(posthoc)
                                               sum_sq      df          F    PR(>F)
    C(df['retrait complet ou partiel'])  1.306261e+05     1.0  14.333277  0.000156
    Residual                             2.515321e+07  2760.0        NaN       NaN
             Multiple Comparison of Means - Tukey HSD, FWER=0.05         
    =====================================================================
         group1          group2     meandiff p-adj  lower   upper  reject
    ---------------------------------------------------------------------
    retrait complet retrait partiel  18.5395 0.0002 8.9374 28.1415   True
    ---------------------------------------------------------------------
    
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Les contrats qui sont vidés complètement ont beaucoup moins d'actions initialement à leur activation</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Les contrats qui sont vidés complètement ont beaucoup moins d'actions initialement à leur activation

    "))

    Les contrats qui sont vidés complètement ont beaucoup moins d'actions initialement à leur activation

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<center><h2>ANOVA moyenne des nombres d'actions par souscription par personne en fonction du retrait total ou pas des actions par contrat </h2></center>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    ANOVA moyenne des nombres d'actions par souscription par personne en fonction du retrait total ou pas des actions par contrat

    "))

    ANOVA moyenne des nombres d'actions par souscription par personne en fonction du retrait total ou pas des actions par contrat

    In [ ]:
    Copied!
    import pandas as pd
    import statsmodels.api as sm
    from statsmodels.formula.api import ols
    from statsmodels.stats.multicomp import pairwise_tukeyhsd
    
    # Charger les données à partir du DataFrame donné (df_retrait)
    df = df_retrait
    df = df.dropna(subset=['Nombre moyen action par souscription', 'retrait complet ou partiel'])
    # Effectuer l'ANOVA
    model = ols("df['Nombre moyen action par souscription'] ~ C(df['retrait complet ou partiel'])", data=df).fit()
    anova_table = sm.stats.anova_lm(model, typ=2)
    
    # Effectuer les comparaisons post hoc (méthode de Tukey)
    posthoc = pairwise_tukeyhsd(df['Nombre moyen action par souscription'], df['retrait complet ou partiel'])
    
    # Afficher la table ANOVA
    print(anova_table)
    
    # Afficher les comparaisons post hoc
    print(posthoc)
    
    import pandas as pd import statsmodels.api as sm from statsmodels.formula.api import ols from statsmodels.stats.multicomp import pairwise_tukeyhsd # Charger les données à partir du DataFrame donné (df_retrait) df = df_retrait df = df.dropna(subset=['Nombre moyen action par souscription', 'retrait complet ou partiel']) # Effectuer l'ANOVA model = ols("df['Nombre moyen action par souscription'] ~ C(df['retrait complet ou partiel'])", data=df).fit() anova_table = sm.stats.anova_lm(model, typ=2) # Effectuer les comparaisons post hoc (méthode de Tukey) posthoc = pairwise_tukeyhsd(df['Nombre moyen action par souscription'], df['retrait complet ou partiel']) # Afficher la table ANOVA print(anova_table) # Afficher les comparaisons post hoc print(posthoc)
                                               sum_sq      df         F    PR(>F)
    C(df['retrait complet ou partiel'])  1.552296e+02     1.0  0.025288  0.873669
    Residual                             1.077901e+07  1756.0       NaN       NaN
             Multiple Comparison of Means - Tukey HSD, FWER=0.05          
    ======================================================================
         group1          group2     meandiff p-adj   lower   upper  reject
    ----------------------------------------------------------------------
    retrait complet retrait partiel  -0.8086 0.8737 -10.7808 9.1637  False
    ----------------------------------------------------------------------
    
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4> Ce sont les plus petits actionnaires qui vident les contrats complètement</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Ce sont les plus petits actionnaires qui vident les contrats complètement

    "))

    Ce sont les plus petits actionnaires qui vident les contrats complètement

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<center><h2>ANOVA moyenne des nombres d'actions en fonction du retrait définitif ou pas des actions </h2></center>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    ANOVA moyenne des nombres d'actions en fonction du retrait définitif ou pas des actions

    "))

    ANOVA moyenne des nombres d'actions en fonction du retrait définitif ou pas des actions

    In [ ]:
    Copied!
    df_retrait.rename(columns={"Nombre d'actions à l'acquisition_y": "nombre_action_totale"}, inplace=True)
    
    df_retrait.rename(columns={"Nombre d'actions à l'acquisition_y": "nombre_action_totale"}, inplace=True)
    In [ ]:
    Copied!
    import pandas as pd
    import statsmodels.api as sm
    from statsmodels.formula.api import ols
    from statsmodels.stats.multicomp import pairwise_tukeyhsd
    
    # Charger les données à partir du DataFrame donné (df_retrait)
    df = df_retrait.copy()
    df = df.dropna(subset=["nombre_action_totale", 'nature du retrait'])
    
    # Effectuer l'ANOVA
    model = ols("df['nombre_action_totale'] ~ C(df['nature du retrait'])", data=df).fit()
    anova_table = sm.stats.anova_lm(model, typ=2)
    
    # Effectuer les comparaisons post hoc (méthode de Tukey)
    posthoc = pairwise_tukeyhsd(df["nombre_action_totale"], df['nature du retrait'])
    
    # Afficher la table ANOVA
    print(anova_table)
    
    # Afficher les comparaisons post hoc
    print(posthoc)
    
    import pandas as pd import statsmodels.api as sm from statsmodels.formula.api import ols from statsmodels.stats.multicomp import pairwise_tukeyhsd # Charger les données à partir du DataFrame donné (df_retrait) df = df_retrait.copy() df = df.dropna(subset=["nombre_action_totale", 'nature du retrait']) # Effectuer l'ANOVA model = ols("df['nombre_action_totale'] ~ C(df['nature du retrait'])", data=df).fit() anova_table = sm.stats.anova_lm(model, typ=2) # Effectuer les comparaisons post hoc (méthode de Tukey) posthoc = pairwise_tukeyhsd(df["nombre_action_totale"], df['nature du retrait']) # Afficher la table ANOVA print(anova_table) # Afficher les comparaisons post hoc print(posthoc)
                                      sum_sq      df         F    PR(>F)
    C(df['nature du retrait'])  2.898909e+05     1.0  9.347905  0.002266
    Residual                    5.445589e+07  1756.0       NaN       NaN
              Multiple Comparison of Means - Tukey HSD, FWER=0.05          
    =======================================================================
          group1           group2     meandiff p-adj   lower  upper  reject
    -----------------------------------------------------------------------
    retrait définitif retrait partiel  57.9613 0.0023 20.7797 95.143   True
    -----------------------------------------------------------------------
    
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4> Les personnes qui font des retraits défintifs ont généralement moins d'actions (221 en moins en moyenne)</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Les personnes qui font des retraits défintifs ont généralement moins d'actions (221 en moins en moyenne)

    "))

    Les personnes qui font des retraits défintifs ont généralement moins d'actions (221 en moins en moyenne)

    In [ ]:
    Copied!
    df_RFsous = df2.copy()
    df_RFsous= df_RFsous[df_RFsous["Nature du mouvement"]== "Souscription"]
    
    df_RFsous["catégorie souscription"] = df_RFsous.apply( lambda row : "Souscription de 5 actions ou moins" if row["Nombre d'actions à l'acquisition"] <=5
                                              else "Souscription de 6 à 50 actions" if row["Nombre d'actions à l'acquisition"] <= 50
                                              else "Souscriptions de 51 à 100 actions" if row["Nombre d'actions à l'acquisition"] <= 100
                                              else "Souscriptions de plus de 100 actions",
                                              axis = 1) 
    
    df_RFsous = df2.copy() df_RFsous= df_RFsous[df_RFsous["Nature du mouvement"]== "Souscription"] df_RFsous["catégorie souscription"] = df_RFsous.apply( lambda row : "Souscription de 5 actions ou moins" if row["Nombre d'actions à l'acquisition"] <=5 else "Souscription de 6 à 50 actions" if row["Nombre d'actions à l'acquisition"] <= 50 else "Souscriptions de 51 à 100 actions" if row["Nombre d'actions à l'acquisition"] <= 100 else "Souscriptions de plus de 100 actions", axis = 1)
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<center><h2>Test Chi-2 pour tester la relation entre les catégories de souscriptions (différentes catégories de nombres d'actions par souscription) avec le fait de demander un reçus fiscal</h2></center>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Test Chi-2 pour tester la relation entre les catégories de souscriptions (différentes catégories de nombres d'actions par souscription) avec le fait de demander un reçus fiscal

    "))

    Test Chi-2 pour tester la relation entre les catégories de souscriptions (différentes catégories de nombres d'actions par souscription) avec le fait de demander un reçus fiscal

    In [ ]:
    Copied!
    import pandas as pd
    from scipy.stats import chi2_contingency
    
    # Créer un tableau de contingence à partir des deux variables catégorielles
    table = pd.crosstab(df_RFsous["catégorie souscription"], df_RFsous["A fait l'objet d'un reçu fiscal_1"])
    
    # Effectuer le test du chi-carré
    chi2, p_value, dof, expected = chi2_contingency(table)
    
    # Afficher les résultats
    print("Test du chi-carré")
    print("Valeur de chi2 :", chi2)
    print("P-valeur :", p_value)
    print("Degrés de liberté :", dof)
    
    import pandas as pd from scipy.stats import chi2_contingency # Créer un tableau de contingence à partir des deux variables catégorielles table = pd.crosstab(df_RFsous["catégorie souscription"], df_RFsous["A fait l'objet d'un reçu fiscal_1"]) # Effectuer le test du chi-carré chi2, p_value, dof, expected = chi2_contingency(table) # Afficher les résultats print("Test du chi-carré") print("Valeur de chi2 :", chi2) print("P-valeur :", p_value) print("Degrés de liberté :", dof)
    Test du chi-carré
    Valeur de chi2 : 1.5037293365068827
    P-valeur : 0.6814098692768409
    Degrés de liberté : 3
    
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Il n'y a aucun lien : regarder la P-valeur, elle est bien supérieure à 0,05 </h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Il n'y a aucun lien : regarder la P-valeur, elle est bien supérieure à 0,05

    "))

    Il n'y a aucun lien : regarder la P-valeur, elle est bien supérieure à 0,05

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<center><h2>ANOVA  pour tester la relation entre le nombre d'actions d'une souscription avec le fait de demander un reçu fiscal</h2></center>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    ANOVA pour tester la relation entre le nombre d'actions d'une souscription avec le fait de demander un reçu fiscal

    "))

    ANOVA pour tester la relation entre le nombre d'actions d'une souscription avec le fait de demander un reçu fiscal

    In [ ]:
    Copied!
    df_RFsous.columns
    df_RFsous.rename(columns={"Nombre d'actions à l'acquisition": "nombre_actions"}, inplace=True)
    df_RFsous.rename(columns={"A fait l'objet d'un reçu fiscal": "RF"}, inplace=True)
    
    df_RFsous.columns df_RFsous.rename(columns={"Nombre d'actions à l'acquisition": "nombre_actions"}, inplace=True) df_RFsous.rename(columns={"A fait l'objet d'un reçu fiscal": "RF"}, inplace=True)
    In [ ]:
    Copied!
    import pandas as pd
    import statsmodels.api as sm
    from statsmodels.formula.api import ols
    from statsmodels.stats.multicomp import pairwise_tukeyhsd
    
    # Charger les données à partir du DataFrame donné (df_retrait)
    df = df_RFsous.copy()
    df = df.dropna(subset=["RF", "nombre_actions"])
    
    # Effectuer l'ANOVA
    model = ols("df['nombre_actions'] ~ C(df['RF'])", data=df).fit()
    anova_table = sm.stats.anova_lm(model, typ=2)
    
    # Effectuer les comparaisons post hoc (méthode de Tukey)
    posthoc = pairwise_tukeyhsd(df["nombre_actions"], df["RF"])
    
    # Afficher la table ANOVA
    print(anova_table)
    
    # Afficher les comparaisons post hoc
    print(posthoc)
    
    import pandas as pd import statsmodels.api as sm from statsmodels.formula.api import ols from statsmodels.stats.multicomp import pairwise_tukeyhsd # Charger les données à partir du DataFrame donné (df_retrait) df = df_RFsous.copy() df = df.dropna(subset=["RF", "nombre_actions"]) # Effectuer l'ANOVA model = ols("df['nombre_actions'] ~ C(df['RF'])", data=df).fit() anova_table = sm.stats.anova_lm(model, typ=2) # Effectuer les comparaisons post hoc (méthode de Tukey) posthoc = pairwise_tukeyhsd(df["nombre_actions"], df["RF"]) # Afficher la table ANOVA print(anova_table) # Afficher les comparaisons post hoc print(posthoc)
                       sum_sq       df         F    PR(>F)
    C(df['RF'])  1.238011e+04      1.0  1.344316  0.246291
    Residual     1.554978e+08  16885.0       NaN       NaN
    Multiple Comparison of Means - Tukey HSD, FWER=0.05
    ===================================================
    group1 group2 meandiff p-adj   lower  upper  reject
    ---------------------------------------------------
         0      1  -2.0308 0.2463 -5.4638 1.4023  False
    ---------------------------------------------------
    
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Il n'y a aucun lien entre le nombre de d'actions par souscription et le fait de demander un reçu fiscal pour cette souscription (différence du nombre d'actions trop minime)</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Il n'y a aucun lien entre le nombre de d'actions par souscription et le fait de demander un reçu fiscal pour cette souscription (différence du nombre d'actions trop minime)

    "))

    Il n'y a aucun lien entre le nombre de d'actions par souscription et le fait de demander un reçu fiscal pour cette souscription (différence du nombre d'actions trop minime)

    In [ ]:
    Copied!
    df_affecsous = df2.copy()
    
    df_affecsous = df2.copy()
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<center><h2>Test du lien entre le type d'affectation des actions de la souscription et le nombre d'actions de la souscription</h2></center>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Test du lien entre le type d'affectation des actions de la souscription et le nombre d'actions de la souscription

    "))

    Test du lien entre le type d'affectation des actions de la souscription et le nombre d'actions de la souscription

    In [ ]:
    Copied!
    import pandas as pd
    from scipy.stats import chi2_contingency
    
    # Créer un tableau de contingence à partir des deux variables catégorielles
    table = pd.crosstab(df_affecsous ["catégorie souscription"], df_affecsous ["Type affectation"])
    
    # Effectuer le test du chi-carré
    chi2, p_value, dof, expected = chi2_contingency(table)
    
    # Afficher les résultats
    print("Test du chi-carré")
    print("Valeur de chi2 :", chi2)
    print("P-valeur :", p_value)
    print("Degrés de liberté :", dof)
    
    import pandas as pd from scipy.stats import chi2_contingency # Créer un tableau de contingence à partir des deux variables catégorielles table = pd.crosstab(df_affecsous ["catégorie souscription"], df_affecsous ["Type affectation"]) # Effectuer le test du chi-carré chi2, p_value, dof, expected = chi2_contingency(table) # Afficher les résultats print("Test du chi-carré") print("Valeur de chi2 :", chi2) print("P-valeur :", p_value) print("Degrés de liberté :", dof)
    Test du chi-carré
    Valeur de chi2 : 5.444360222968541
    P-valeur : 0.48820687336541335
    Degrés de liberté : 6
    
    In [ ]:
    Copied!
    df_affecsous.rename(columns={"Nombre d'actions à l'acquisition": "nombre_actions"}, inplace=True)
    
    df_affecsous.rename(columns={"Nombre d'actions à l'acquisition": "nombre_actions"}, inplace=True)
    In [ ]:
    Copied!
    import pandas as pd
    import statsmodels.api as sm
    from statsmodels.formula.api import ols
    from statsmodels.stats.multicomp import pairwise_tukeyhsd
    
    # Charger les données à partir du DataFrame donné (df_retrait)
    df = df_affecsous.copy()
    df = df.dropna(subset=["nombre_actions", "Type affectation"])
    
    # Effectuer l'ANOVA
    model = ols("df['nombre_actions'] ~ C(df['Type affectation'])", data=df).fit()
    anova_table = sm.stats.anova_lm(model, typ=2)
    
    # Effectuer les comparaisons post hoc (méthode de Tukey)
    posthoc = pairwise_tukeyhsd(df["nombre_actions"], df["Type affectation"])
    
    # Afficher la table ANOVA
    print(anova_table)
    
    # Afficher les comparaisons post hoc
    print(posthoc)
    
    import pandas as pd import statsmodels.api as sm from statsmodels.formula.api import ols from statsmodels.stats.multicomp import pairwise_tukeyhsd # Charger les données à partir du DataFrame donné (df_retrait) df = df_affecsous.copy() df = df.dropna(subset=["nombre_actions", "Type affectation"]) # Effectuer l'ANOVA model = ols("df['nombre_actions'] ~ C(df['Type affectation'])", data=df).fit() anova_table = sm.stats.anova_lm(model, typ=2) # Effectuer les comparaisons post hoc (méthode de Tukey) posthoc = pairwise_tukeyhsd(df["nombre_actions"], df["Type affectation"]) # Afficher la table ANOVA print(anova_table) # Afficher les comparaisons post hoc print(posthoc)
                                     sum_sq       df         F    PR(>F)
    C(df['Type affectation'])  9.028781e+03      2.0  0.490163  0.612535
    Residual                   1.555012e+08  16884.0       NaN       NaN
          Multiple Comparison of Means - Tukey HSD, FWER=0.05      
    ===============================================================
       group1       group2    meandiff p-adj   lower  upper  reject
    ---------------------------------------------------------------
    dédié projet dédié région   1.7424 0.5968 -2.4745 5.9592  False
    dédié projet   non dédié    0.5327 0.9532 -3.7033 4.7686  False
    dédié région   non dédié   -1.2097 0.7844 -5.4796 3.0602  False
    ---------------------------------------------------------------
    
    In [ ]:
    Copied!
    df_affecsousct = df_affecsous.groupby("Type affectation")["nombre_actions"].mean().to_frame()
    df_affecsousct
    
    df_affecsousct = df_affecsous.groupby("Type affectation")["nombre_actions"].mean().to_frame() df_affecsousct
    Out[ ]:
    nombre_actions
    Type affectation
    dédié projet 52.055488
    dédié région 53.797857
    non dédié 52.588150
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Les souscriptions avec le moins d'actions voient leur capital le plus souvent alloué à des projets, puis celles qui ont un peu plus d'actions (18 actions de plus en moyenne que les souscriptions dédiées projets) sont allouées aux régions, puis les soucriptions avec le plus d'actions sont souvent non-dédiées</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Les souscriptions avec le moins d'actions voient leur capital le plus souvent alloué à des projets, puis celles qui ont un peu plus d'actions (18 actions de plus en moyenne que les souscriptions dédiées projets) sont allouées aux régions, puis les soucriptions avec le plus d'actions sont souvent non-dédiées

    "))

    Les souscriptions avec le moins d'actions voient leur capital le plus souvent alloué à des projets, puis celles qui ont un peu plus d'actions (18 actions de plus en moyenne que les souscriptions dédiées projets) sont allouées aux régions, puis les soucriptions avec le plus d'actions sont souvent non-dédiées

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<center><h2>ANOVA testant le lien entre la catégorie d'engagement et la  variation du nombre d'actions prises entre la 2eme et 1ere souscription.</h2></center>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    ANOVA testant le lien entre la catégorie d'engagement et la variation du nombre d'actions prises entre la 2eme et 1ere souscription.

    "))

    ANOVA testant le lien entre la catégorie d'engagement et la variation du nombre d'actions prises entre la 2eme et 1ere souscription.

    In [ ]:
    Copied!
    df_variationactions10 = df_variationactions10.merge(df_MS[["multi-casquette ?", "ID du contact"]], on = "ID du contact", how = 'left')
    df_variationactions10 = df_variationactions10[["multi-casquette ?", "ID du contact", "diff_actions_souscriptions_2_1"]]
    
    
    import pandas as pd
    import statsmodels.api as sm
    from statsmodels.formula.api import ols
    from statsmodels.stats.multicomp import pairwise_tukeyhsd
    
    # Charger les données à partir du DataFrame donné (df_retrait)
    df = df_variationactions10.copy()
    df = df.dropna(subset=["diff_actions_souscriptions_2_1", "multi-casquette ?"])
    
    # Effectuer l'ANOVA
    model = ols("df['diff_actions_souscriptions_2_1'] ~ C(df['multi-casquette ?'])", data=df).fit()
    anova_table = sm.stats.anova_lm(model, typ=2)
    
    # Effectuer les comparaisons post hoc (méthode de Tukey)
    posthoc = pairwise_tukeyhsd(df["diff_actions_souscriptions_2_1"], df["multi-casquette ?"])
    
    # Afficher la table ANOVA
    print(anova_table)
    
    # Afficher les comparaisons post hoc
    print(posthoc)
    
    df_variationactions10 = df_variationactions10.merge(df_MS[["multi-casquette ?", "ID du contact"]], on = "ID du contact", how = 'left') df_variationactions10 = df_variationactions10[["multi-casquette ?", "ID du contact", "diff_actions_souscriptions_2_1"]] import pandas as pd import statsmodels.api as sm from statsmodels.formula.api import ols from statsmodels.stats.multicomp import pairwise_tukeyhsd # Charger les données à partir du DataFrame donné (df_retrait) df = df_variationactions10.copy() df = df.dropna(subset=["diff_actions_souscriptions_2_1", "multi-casquette ?"]) # Effectuer l'ANOVA model = ols("df['diff_actions_souscriptions_2_1'] ~ C(df['multi-casquette ?'])", data=df).fit() anova_table = sm.stats.anova_lm(model, typ=2) # Effectuer les comparaisons post hoc (méthode de Tukey) posthoc = pairwise_tukeyhsd(df["diff_actions_souscriptions_2_1"], df["multi-casquette ?"]) # Afficher la table ANOVA print(anova_table) # Afficher les comparaisons post hoc print(posthoc)
                                      sum_sq      df         F   PR(>F)
    C(df['multi-casquette ?'])  4.214267e+03     3.0  0.074983  0.97346
    Residual                    6.536385e+07  3489.0       NaN      NaN
                    Multiple Comparison of Means - Tukey HSD, FWER=0.05                
    ===================================================================================
            group1                group2        meandiff p-adj   lower    upper  reject
    -----------------------------------------------------------------------------------
    Actionnaire uniquement Actionnaire-adhérent   2.7392 0.9866 -18.0381 23.5166  False
    Actionnaire uniquement Actionnaire-donateur   4.3205 0.9666 -19.5503 28.1913  False
    Actionnaire uniquement    Triple-engagement   3.0473 0.9812 -17.5134  23.608  False
      Actionnaire-adhérent Actionnaire-donateur   1.5812 0.9962 -16.8008 19.9632  False
      Actionnaire-adhérent    Triple-engagement    0.308 0.9999  -13.506  14.122  False
      Actionnaire-donateur    Triple-engagement  -1.2732 0.9979   -19.41 16.8636  False
    -----------------------------------------------------------------------------------
    
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Il n'y a aucun lien entre la catégorie d'engagement de l'actionnaire (multi-engagemenet, etc) et le nombre d'actions qu'il reprend lors de sa deuxième souscription par rapport à la première.</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Il n'y a aucun lien entre la catégorie d'engagement de l'actionnaire (multi-engagemenet, etc) et le nombre d'actions qu'il reprend lors de sa deuxième souscription par rapport à la première.

    "))

    Il n'y a aucun lien entre la catégorie d'engagement de l'actionnaire (multi-engagemenet, etc) et le nombre d'actions qu'il reprend lors de sa deuxième souscription par rapport à la première.

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<center><h2>Test Chi-carré testant le lien entre la catégorie d'engagement et la catégorie de variation du nombre d'actions prises entre la 2eme et 1ere souscription.</h2></center>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Test Chi-carré testant le lien entre la catégorie d'engagement et la catégorie de variation du nombre d'actions prises entre la 2eme et 1ere souscription.

    "))

    Test Chi-carré testant le lien entre la catégorie d'engagement et la catégorie de variation du nombre d'actions prises entre la 2eme et 1ere souscription.

    In [ ]:
    Copied!
    conditions = [
        (df_variationactions10["diff_actions_souscriptions_2_1"] > 0),
        (df_variationactions10["diff_actions_souscriptions_2_1"] == 0),
        (df_variationactions10["diff_actions_souscriptions_2_1"] < 0)
    ]
    
    choices = ['augmentation', 'stagnation', 'diminution']
    
    df_variationactions10['Catégories variation'] = np.select(conditions, choices, default='diminution')
    
    import pandas as pd
    from scipy.stats import chi2_contingency
    
    # Créer un tableau de contingence à partir des deux variables catégorielles
    table = pd.crosstab(df_variationactions10['Catégories variation'], df_variationactions10["multi-casquette ?"])
    
    # Effectuer le test du chi-carré
    chi2, p_value, dof, expected = chi2_contingency(table)
    
    # Afficher les résultats
    print("Test du chi-carré")
    print("Valeur de chi2 :", chi2)
    print("P-valeur :", p_value)
    print("Degrés de liberté :", dof)
    
    conditions = [ (df_variationactions10["diff_actions_souscriptions_2_1"] > 0), (df_variationactions10["diff_actions_souscriptions_2_1"] == 0), (df_variationactions10["diff_actions_souscriptions_2_1"] < 0) ] choices = ['augmentation', 'stagnation', 'diminution'] df_variationactions10['Catégories variation'] = np.select(conditions, choices, default='diminution') import pandas as pd from scipy.stats import chi2_contingency # Créer un tableau de contingence à partir des deux variables catégorielles table = pd.crosstab(df_variationactions10['Catégories variation'], df_variationactions10["multi-casquette ?"]) # Effectuer le test du chi-carré chi2, p_value, dof, expected = chi2_contingency(table) # Afficher les résultats print("Test du chi-carré") print("Valeur de chi2 :", chi2) print("P-valeur :", p_value) print("Degrés de liberté :", dof)
    Test du chi-carré
    Valeur de chi2 : 13.14554323291345
    P-valeur : 0.04078205664946092
    Degrés de liberté : 6
    
    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<h4>Il n'y a également aucun lien entre le fait de faire augmenter, diminuer ou stagner le nombre d'actions prises lors de la 2eme souscription par rapport à la première et le fait d'avoir différents types de multi-engagement</h4>"))
    
    from IPython.display import display, Markdown, HTML # Afficher un titre avec une taille de police plus grande display(HTML("

    Il n'y a également aucun lien entre le fait de faire augmenter, diminuer ou stagner le nombre d'actions prises lors de la 2eme souscription par rapport à la première et le fait d'avoir différents types de multi-engagement

    "))

    Il n'y a également aucun lien entre le fait de faire augmenter, diminuer ou stagner le nombre d'actions prises lors de la 2eme souscription par rapport à la première et le fait d'avoir différents types de multi-engagement

    In [ ]:
    Copied!
    from IPython.display import display, Markdown, HTML
    
    
    # Insérer un saut de page
    display(HTML("<div style='page-break-before: always;'></div>"))
    # Afficher un titre avec une taille de police plus grande
    display(HTML("<center><h1>Annexes</h1><center>"))
    
    from IPython.display import display, Markdown, HTML # Insérer un saut de page display(HTML("
    ")) # Afficher un titre avec une taille de police plus grande display(HTML("

    Annexes

    "))

    Annexes

    In [ ]:
    Copied!
    from IPython.display import display, HTML
    
    # Afficher un titre centré avec une taille de police plus grande
    display(HTML('<center><h2>Focus annuel sur le nombre  d\'actions et de souscriptions</h2></center>'))
    
    from IPython.display import display, HTML # Afficher un titre centré avec une taille de police plus grande display(HTML('

    Focus annuel sur le nombre d\'actions et de souscriptions

    '))

    Focus annuel sur le nombre d'actions et de souscriptions

    In [ ]:
    Copied!
    from IPython.display import display, HTML
    
    # Afficher un titre centré avec une taille de police plus grande
    display(HTML('<h3>Pour les graphiques qui suivent nous avons considéré la "date effective du mouvement" sur l\'objet "mouvements de titres" qui est rattaché à l\'objet "contrat"</h3>'))
    
    from IPython.display import display, HTML # Afficher un titre centré avec une taille de police plus grande display(HTML('

    Pour les graphiques qui suivent nous avons considéré la "date effective du mouvement" sur l\'objet "mouvements de titres" qui est rattaché à l\'objet "contrat"

    '))

    Pour les graphiques qui suivent nous avons considéré la "date effective du mouvement" sur l'objet "mouvements de titres" qui est rattaché à l'objet "contrat"

    In [ ]:
    Copied!
    df_souscription_an = df2["répartition année"].value_counts().to_frame()
    df_souscription_an = df_souscription_an.sort_values(by="répartition année")
    
    import matplotlib.pyplot as plt
    
    # Data
    annee_souscription = df_souscription_an.index
    nombre_souscriptions = df_souscription_an['count']
    
    # Create the bar plot
    plt.figure(figsize=(10, 6))
    plt.bar(annee_souscription, nombre_souscriptions, color='skyblue')
    
    # Add data labels above each bar
    for i, v in enumerate(nombre_souscriptions):
        plt.text(annee_souscription[i], v, str(v), ha='center', va='bottom', fontsize=10)
    
    # Title and labels for axes
    plt.title("Nombre de souscriptions par année")
    plt.xlabel("Années de souscription")
    plt.ylabel("Nombre de souscriptions")
    
    # Rotate x-axis labels for better readability
    plt.xticks(rotation=45)
    
    # Display the plot
    plt.tight_layout()
    plt.show()
    
    df_souscription_an = df2["répartition année"].value_counts().to_frame() df_souscription_an = df_souscription_an.sort_values(by="répartition année") import matplotlib.pyplot as plt # Data annee_souscription = df_souscription_an.index nombre_souscriptions = df_souscription_an['count'] # Create the bar plot plt.figure(figsize=(10, 6)) plt.bar(annee_souscription, nombre_souscriptions, color='skyblue') # Add data labels above each bar for i, v in enumerate(nombre_souscriptions): plt.text(annee_souscription[i], v, str(v), ha='center', va='bottom', fontsize=10) # Title and labels for axes plt.title("Nombre de souscriptions par année") plt.xlabel("Années de souscription") plt.ylabel("Nombre de souscriptions") # Rotate x-axis labels for better readability plt.xticks(rotation=45) # Display the plot plt.tight_layout() plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    df_action_an = df2.groupby('répartition année')["Nombre d'actions à l'acquisition"].sum().reset_index()
    
    import matplotlib.pyplot as plt
    
    # Données
    annee_rachat = df_action_an['répartition année']
    nombre_actions = df_action_an["Nombre d'actions à l'acquisition"]
    
    # Créer le diagramme en bâtons
    plt.figure(figsize=(10, 6))
    plt.bar(annee_rachat, nombre_actions, width=0.8, color='skyblue')  # Increase the width parameter for wider bars
    
    # Titre et étiquettes des axes
    plt.title("Nombre total d'actions prises par année")
    plt.xlabel("Années")
    plt.ylabel("Nombre total d'actions à l'acquisition")
    
    # Afficher les valeurs au-dessus de chaque barre
    for i, v in enumerate(nombre_actions):
        plt.text(annee_rachat[i], v + 100, str(int(v)), ha='center', va='bottom', fontsize=8)
    
    # Faire pivoter les étiquettes de l'axe des x pour une meilleure lisibilité
    plt.xticks(rotation=45)
    
    # Afficher le diagramme en bâtons
    plt.tight_layout()
    plt.show()
    
    df_action_an = df2.groupby('répartition année')["Nombre d'actions à l'acquisition"].sum().reset_index() import matplotlib.pyplot as plt # Données annee_rachat = df_action_an['répartition année'] nombre_actions = df_action_an["Nombre d'actions à l'acquisition"] # Créer le diagramme en bâtons plt.figure(figsize=(10, 6)) plt.bar(annee_rachat, nombre_actions, width=0.8, color='skyblue') # Increase the width parameter for wider bars # Titre et étiquettes des axes plt.title("Nombre total d'actions prises par année") plt.xlabel("Années") plt.ylabel("Nombre total d'actions à l'acquisition") # Afficher les valeurs au-dessus de chaque barre for i, v in enumerate(nombre_actions): plt.text(annee_rachat[i], v + 100, str(int(v)), ha='center', va='bottom', fontsize=8) # Faire pivoter les étiquettes de l'axe des x pour une meilleure lisibilité plt.xticks(rotation=45) # Afficher le diagramme en bâtons plt.tight_layout() plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    df_actionmean_an = df2.groupby('répartition année')["Nombre d'actions à l'acquisition"].mean().reset_index()
    import matplotlib.pyplot as plt
    
    # Données du tableau
    annee_acquisition = df_actionmean_an['répartition année']
    nombre_actions_acquisition = df_actionmean_an["Nombre d'actions à l'acquisition"]
    
    # Créer le diagramme en bâtons
    plt.bar(annee_acquisition, nombre_actions_acquisition)
    
    # Ajouter les étiquettes de valeurs sur chaque barre
    for i in range(len(annee_acquisition)):
        plt.text(annee_acquisition[i], nombre_actions_acquisition[i], str(int(nombre_actions_acquisition[i])),
                 ha='center', va='bottom')
    
    # Titre et étiquettes des axes
    plt.title("Nombre moyen d'actions par souscription par année")
    plt.xlabel("Année d'acquisition")
    plt.ylabel("Nombre moyen d'actions à l'acquisition")
    
    # Incliner les années sur l'axe des abscisses
    plt.xticks(rotation=45)
    # Afficher le diagramme
    plt.tight_layout()
    plt.show()
    
    df_actionmean_an = df2.groupby('répartition année')["Nombre d'actions à l'acquisition"].mean().reset_index() import matplotlib.pyplot as plt # Données du tableau annee_acquisition = df_actionmean_an['répartition année'] nombre_actions_acquisition = df_actionmean_an["Nombre d'actions à l'acquisition"] # Créer le diagramme en bâtons plt.bar(annee_acquisition, nombre_actions_acquisition) # Ajouter les étiquettes de valeurs sur chaque barre for i in range(len(annee_acquisition)): plt.text(annee_acquisition[i], nombre_actions_acquisition[i], str(int(nombre_actions_acquisition[i])), ha='center', va='bottom') # Titre et étiquettes des axes plt.title("Nombre moyen d'actions par souscription par année") plt.xlabel("Année d'acquisition") plt.ylabel("Nombre moyen d'actions à l'acquisition") # Incliner les années sur l'axe des abscisses plt.xticks(rotation=45) # Afficher le diagramme plt.tight_layout() plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    df_perteaction_an = df_rachat.groupby('année rachat')["Nombre d'actions échangées"].sum().reset_index()
    import matplotlib.pyplot as plt
    
    # Données
    annee_rachat = df_perteaction_an['année rachat']
    nombre_actions = df_perteaction_an['Nombre d\'actions échangées']
    
    # Créer le diagramme en bâtons
    plt.figure(figsize=(10, 6))
    plt.bar(annee_rachat, nombre_actions, color='skyblue')
    
    # Titre et étiquettes des axes
    plt.title("Nombre d'actions retirées par année de rachat")
    plt.xlabel("Années de rachat")
    plt.ylabel("Nombre d'actions retirées")
    
    # Afficher les valeurs au-dessus de chaque barre
    for i, v in enumerate(nombre_actions):
        plt.text(annee_rachat[i], v + 100, str(int(v)), ha='center', va='bottom', fontsize=8)
    
    # Faire pivoter les étiquettes de l'axe des x pour une meilleure lisibilité
    plt.xticks(rotation=45)
    
    # Afficher le diagramme en bâtons
    plt.tight_layout()
    plt.show()
    
    df_perteaction_an = df_rachat.groupby('année rachat')["Nombre d'actions échangées"].sum().reset_index() import matplotlib.pyplot as plt # Données annee_rachat = df_perteaction_an['année rachat'] nombre_actions = df_perteaction_an['Nombre d\'actions échangées'] # Créer le diagramme en bâtons plt.figure(figsize=(10, 6)) plt.bar(annee_rachat, nombre_actions, color='skyblue') # Titre et étiquettes des axes plt.title("Nombre d'actions retirées par année de rachat") plt.xlabel("Années de rachat") plt.ylabel("Nombre d'actions retirées") # Afficher les valeurs au-dessus de chaque barre for i, v in enumerate(nombre_actions): plt.text(annee_rachat[i], v + 100, str(int(v)), ha='center', va='bottom', fontsize=8) # Faire pivoter les étiquettes de l'axe des x pour une meilleure lisibilité plt.xticks(rotation=45) # Afficher le diagramme en bâtons plt.tight_layout() plt.show()
    No description has been provided for this image
    In [ ]:
    Copied!
    df_donaction_an = df_dongraph.groupby('année rachat')["Nombre d'actions échangées"].sum().reset_index()
    
    import matplotlib.pyplot as plt
    
    # Données du tableau
    annee_rachat = df_donaction_an['année rachat']
    nombre_actions = df_donaction_an['Nombre d\'actions échangées']
    
    # Créer le diagramme en bâtons
    plt.bar(annee_rachat, nombre_actions)
    
    # Ajouter les étiquettes de valeur au-dessus des barres
    for x, y in zip(annee_rachat, nombre_actions):
        plt.text(x, y, str(int(y)), ha='center', va='bottom')
    
    # Titre et étiquettes des axes
    plt.title("Nombre d'actions données par année (Don TDL)")
    plt.xlabel("Années")
    plt.ylabel("Nombre d'actions données")
    
    # Afficher le diagramme
    plt.tight_layout()
    plt.show()
    
    df_donaction_an = df_dongraph.groupby('année rachat')["Nombre d'actions échangées"].sum().reset_index() import matplotlib.pyplot as plt # Données du tableau annee_rachat = df_donaction_an['année rachat'] nombre_actions = df_donaction_an['Nombre d\'actions échangées'] # Créer le diagramme en bâtons plt.bar(annee_rachat, nombre_actions) # Ajouter les étiquettes de valeur au-dessus des barres for x, y in zip(annee_rachat, nombre_actions): plt.text(x, y, str(int(y)), ha='center', va='bottom') # Titre et étiquettes des axes plt.title("Nombre d'actions données par année (Don TDL)") plt.xlabel("Années") plt.ylabel("Nombre d'actions données") # Afficher le diagramme plt.tight_layout() plt.show()
    No description has been provided for this image
    Made with Material for MkDocs